summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <pem@mysql.comhem.se>2004-03-19 19:01:54 +0100
committerunknown <pem@mysql.comhem.se>2004-03-19 19:01:54 +0100
commitd2ad3cff192de352961ec01f5370821690d7173f (patch)
tree8a8b60eab5553d3fb3d8304e77dadd313b4c77e6
parentedf2003009c7fd44c6a8b4a9306685357dbbb399 (diff)
downloadmariadb-git-d2ad3cff192de352961ec01f5370821690d7173f.tar.gz
WL#1366: Use the schema (db) associated with an SP.
Phase 3: Made qualified names work for functions as well. mysql-test/r/sp-security.result: New testcases for functions with qualified names. mysql-test/t/sp-security.test: New testcases for functions with qualified names. sql/item_func.cc: Added error handling for stored function, if it doesn't exist. sql/item_func.h: Set null_value if execution of a stored function fails. sql/mysql_priv.h: Reverted previous change: No optional args for mysql_change_db(). (SPs use a specially tailored function instead.) sql/sp.cc: Copied mysql_change_db() from sql_db.cc and modified specially for SPs. sql/sp_head.cc: Fixed error handling for errors in functions during query/statement execution. sql/sql_db.cc: Reverted previous change: No optional args for mysql_change_db(). (SPs use a specially tailored function instead.) sql/sql_yacc.yy: Reworked the stored function/UDF invokation parsing and added qualified names for stored functions. UDFs now have precedence over stored functions (whith unqualified name). When using an unqualified name, only IDENT_sys is allowed (i.e. no unreserved keywords), since we get unresolvable reduce/reduce conflicts otherwise.
-rw-r--r--mysql-test/r/sp-security.result25
-rw-r--r--mysql-test/t/sp-security.test20
-rw-r--r--sql/item_func.cc15
-rw-r--r--sql/item_func.h6
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sp.cc106
-rw-r--r--sql/sp_head.cc12
-rw-r--r--sql/sql_db.cc95
-rw-r--r--sql/sql_yacc.yy147
9 files changed, 286 insertions, 143 deletions
diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result
index 51439e08782..25bceb0f54f 100644
--- a/mysql-test/r/sp-security.result
+++ b/mysql-test/r/sp-security.result
@@ -10,14 +10,27 @@ insert into db1_secret.t1 values (user(), i);
show procedure status like 'stamp';
Db Name Type Definer Modified Created Security_type Comment
db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
+create function db() returns varchar(64) return database();
+show function status like 'db';
+Db Name Type Definer Modified Created Security_type Comment
+db1_secret db FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
call stamp(1);
select * from t1;
u i
root@localhost 1
+select db();
+db()
+db1_secret
call db1_secret.stamp(2);
+select db1_secret.db();
+db1_secret.db()
+db1_secret
select * from db1_secret.t1;
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
call db1_secret.stamp(3);
+select db1_secret.db();
+db1_secret.db()
+db1_secret
select * from db1_secret.t1;
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
select * from t1;
@@ -29,6 +42,10 @@ alter procedure stamp sql security invoker;
show procedure status like 'stamp';
Db Name Type Definer Modified Created Security_type Comment
db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
+alter function db sql security invoker;
+show function status like 'db';
+Db Name Type Definer Modified Created Security_type Comment
+db1_secret db FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 INVOKER
call stamp(4);
select * from t1;
u i
@@ -36,10 +53,17 @@ root@localhost 1
user1@localhost 2
anon@localhost 3
root@localhost 4
+select db();
+db()
+db1_secret
call db1_secret.stamp(5);
ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
+select db1_secret.db();
+ERROR 42000: Access denied for user: 'user1'@'localhost' to database 'db1_secret'
call db1_secret.stamp(6);
ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
+select db1_secret.db();
+ERROR 42000: Access denied for user: ''@'localhost' to database 'db1_secret'
drop database if exists db2;
create database db2;
use db2;
@@ -74,6 +98,7 @@ s1
2
2
drop procedure db1_secret.stamp;
+drop function db1_secret.db;
drop procedure db2.p;
drop procedure db2.q;
use test;
diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test
index 2d089e72d0b..ae977684129 100644
--- a/mysql-test/t/sp-security.test
+++ b/mysql-test/t/sp-security.test
@@ -21,15 +21,20 @@ use db1_secret;
create table t1 ( u varchar(64), i int );
-# Our test procedure
+# A test procedure and function
create procedure stamp(i int)
insert into db1_secret.t1 values (user(), i);
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show procedure status like 'stamp';
+create function db() returns varchar(64) return database();
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show function status like 'db';
+
# root can, of course
call stamp(1);
select * from t1;
+select db();
connect (con2user1,localhost,user1,,);
connect (con3anon,localhost,anon,,);
@@ -41,6 +46,7 @@ connection con2user1;
# This should work...
call db1_secret.stamp(2);
+select db1_secret.db();
# ...but not this
--error 1044
@@ -53,6 +59,7 @@ connection con3anon;
# This should work...
call db1_secret.stamp(3);
+select db1_secret.db();
# ...but not this
--error 1044
@@ -71,9 +78,14 @@ alter procedure stamp sql security invoker;
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show procedure status like 'stamp';
+alter function db sql security invoker;
+--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
+show function status like 'db';
+
# root still can
call stamp(4);
select * from t1;
+select db();
#
# User1 cannot
@@ -83,6 +95,8 @@ connection con2user1;
# This should not work
--error 1044
call db1_secret.stamp(5);
+--error 1044
+select db1_secret.db();
#
# Anonymous cannot
@@ -92,7 +106,8 @@ connection con3anon;
# This should not work
--error 1044
call db1_secret.stamp(6);
-
+--error 1044
+select db1_secret.db();
#
# BUG#2777
@@ -149,6 +164,7 @@ select * from t2;
# Clean up
connection con1root;
drop procedure db1_secret.stamp;
+drop function db1_secret.db;
drop procedure db2.p;
drop procedure db2.q;
use test;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index fdb0a5e5240..2a74f2801c0 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -3120,7 +3120,11 @@ Item_func_sp::execute(Item **itp)
if (! m_sp)
m_sp= sp_find_function(thd, m_name);
if (! m_sp)
+ {
+ my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
+ "FUNCTION", m_name->m_qname);
DBUG_RETURN(-1);
+ }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
sp_change_security_context(thd, m_sp, &save_ctx);
@@ -3147,6 +3151,8 @@ Item_func_sp::field_type() const
DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns));
DBUG_RETURN(m_sp->m_returns);
}
+ my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
+ "FUNCTION", m_name->m_qname);
DBUG_RETURN(MYSQL_TYPE_STRING);
}
@@ -3162,6 +3168,8 @@ Item_func_sp::result_type() const
{
DBUG_RETURN(m_sp->result());
}
+ my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
+ "FUNCTION", m_name->m_qname);
DBUG_RETURN(STRING_RESULT);
}
@@ -3172,7 +3180,12 @@ Item_func_sp::fix_length_and_dec()
if (! m_sp)
m_sp= sp_find_function(current_thd, m_name);
- if (m_sp)
+ if (! m_sp)
+ {
+ my_printf_error(ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), MYF(0),
+ "FUNCTION", m_name->m_qname);
+ }
+ else
{
switch (m_sp->result()) {
case STRING_RESULT:
diff --git a/sql/item_func.h b/sql/item_func.h
index e68826ca56e..6d313a8ea66 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1107,7 +1107,10 @@ public:
Item *it;
if (execute(&it))
+ {
+ null_value= 1;
return 0.0;
+ }
return it->val();
}
@@ -1116,7 +1119,10 @@ public:
Item *it;
if (execute(&it))
+ {
+ null_value= 1;
return NULL;
+ }
return it->val_str(str);
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 21822e02d29..e17847ebe24 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -445,8 +445,7 @@ int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
int quick_rm_table(enum db_type base,const char *db,
const char *table_name);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
-bool mysql_change_db(THD *thd,const char *name,
- bool empty_is_ok=0, bool no_access_check=0);
+bool mysql_change_db(THD *thd,const char *name);
void mysql_parse(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command);
void free_items(Item *item);
diff --git a/sql/sp.cc b/sql/sp.cc
index 1b58c709e4e..389c627f5f3 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -16,6 +16,7 @@
#include "mysql_priv.h"
+#include "sql_acl.h"
#include "sp.h"
#include "sp_head.h"
#include "sp_cache.h"
@@ -960,19 +961,104 @@ sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen,
}
}
+/*
+ Change database.
+
+ SYNOPSIS
+ sp_change_db()
+ thd Thread handler
+ name Database name
+ empty_is_ok True= it's ok with "" as name
+ no_access_check True= don't do access check
+
+ DESCRIPTION
+ This is the same as mysql_change_db(), but with some extra
+ arguments for Stored Procedure usage; doing implicit "use"
+ when executing an SP in a different database.
+ We also use different error routines, since this might be
+ invoked from a function when executing a query or statement.
+ Note: We would have prefered to reuse mysql_change_db(), but
+ the error handling in particular made that too awkward, so
+ we (reluctantly) have a "copy" here.
+
+ RETURN VALUES
+ 0 ok
+ 1 error
+*/
+
int
-sp_change_db(THD *thd, char *db, bool no_access_check)
+sp_change_db(THD *thd, char *name, bool no_access_check)
{
- int ret;
- ulong dbaccess= thd->db_access; /* mysql_change_db() changes this */
- my_bool nsok= thd->net.no_send_ok; /* mysql_change_db() does send_ok() */
- thd->net.no_send_ok= TRUE;
+ int length, db_length;
+ char *dbname=my_strdup((char*) name,MYF(MY_WME));
+ char path[FN_REFLEN];
+ ulong db_access;
+ HA_CREATE_INFO create;
DBUG_ENTER("sp_change_db");
- DBUG_PRINT("enter", ("db: %s, no_access_check: %d", db, no_access_check));
+ DBUG_PRINT("enter", ("db: %s, no_access_check: %d", name, no_access_check));
- ret= mysql_change_db(thd, db, 1, no_access_check);
+ db_length= (!dbname ? 0 : strip_sp(dbname));
+ if (dbname && db_length)
+ {
+ if ((db_length > NAME_LEN) || check_db_name(dbname))
+ {
+ my_printf_error(ER_WRONG_DB_NAME, ER(ER_WRONG_DB_NAME), MYF(0), dbname);
+ x_free(dbname);
+ DBUG_RETURN(1);
+ }
+ }
- thd->net.no_send_ok= nsok;
- thd->db_access= dbaccess;
- DBUG_RETURN(ret);
+ if (dbname && db_length)
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (! no_access_check)
+ {
+ if (test_all_bits(thd->master_access,DB_ACLS))
+ db_access=DB_ACLS;
+ else
+ db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
+ thd->master_access);
+ if (!(db_access & DB_ACLS) &&
+ (!grant_option || check_grant_db(thd,dbname)))
+ {
+ my_printf_error(ER_DBACCESS_DENIED_ERROR, ER(ER_DBACCESS_DENIED_ERROR),
+ MYF(0),
+ thd->priv_user,
+ thd->priv_host,
+ dbname);
+ mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
+ thd->priv_user,
+ thd->priv_host,
+ dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+#endif
+ (void) sprintf(path,"%s/%s",mysql_data_home,dbname);
+ length=unpack_dirname(path,path); // Convert if not unix
+ if (length && path[length-1] == FN_LIBCHAR)
+ path[length-1]=0; // remove ending '\'
+ if (access(path,F_OK))
+ {
+ my_printf_error(ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR), MYF(0), dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
+
+ x_free(thd->db);
+ thd->db=dbname; // THD::~THD will free this
+ thd->db_length=db_length;
+
+ if (dbname && db_length)
+ {
+ strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
+ load_db_opt(thd, path, &create);
+ thd->db_charset= create.default_table_charset ?
+ create.default_table_charset :
+ thd->variables.collation_server;
+ thd->variables.collation_database= thd->db_charset;
+ }
+ DBUG_RETURN(0);
}
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index ebf74e25bbe..c8be113e2e1 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -389,12 +389,13 @@ sp_head::execute(THD *thd)
continue;
}
}
- } while (ret == 0 && !thd->killed && !thd->query_error);
+ } while (ret == 0 && !thd->killed && !thd->query_error &&
+ !thd->net.report_error);
done:
DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d",
ret, thd->killed, thd->query_error));
- if (thd->killed || thd->query_error)
+ if (thd->killed || thd->query_error || thd->net.report_error)
ret= -1;
/* If the DB has changed, the pointer has changed too, but the
original thd->db will then have been freed */
@@ -553,7 +554,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
ret= execute(thd);
// Don't copy back OUT values if we got an error
- if (ret == 0 && csize > 0)
+ if (ret)
+ {
+ if (thd->net.report_error)
+ send_error(thd, 0, NullS);
+ }
+ else if (csize > 0)
{
List_iterator_fast<Item> li(*args);
Item *it;
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 3ea6821ef80..bc6b30040d6 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -595,8 +595,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
1 error
*/
-bool mysql_change_db(THD *thd, const char *name,
- bool empty_is_ok, bool no_access_check)
+bool mysql_change_db(THD *thd, const char *name)
{
int length, db_length;
char *dbname=my_strdup((char*) name,MYF(MY_WME));
@@ -605,76 +604,62 @@ bool mysql_change_db(THD *thd, const char *name,
HA_CREATE_INFO create;
DBUG_ENTER("mysql_change_db");
- if ((!dbname || !(db_length=strip_sp(dbname))) && !empty_is_ok)
+ if (!dbname || !(db_length=strip_sp(dbname)))
{
x_free(dbname); /* purecov: inspected */
send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
- if (!empty_is_ok || (dbname && db_length))
+ if ((db_length > NAME_LEN) || check_db_name(dbname))
{
- if ((db_length > NAME_LEN) || check_db_name(dbname))
- {
- net_printf(thd, ER_WRONG_DB_NAME, dbname);
- x_free(dbname);
- DBUG_RETURN(1);
- }
+ net_printf(thd, ER_WRONG_DB_NAME, dbname);
+ x_free(dbname);
+ DBUG_RETURN(1);
}
DBUG_PRINT("info",("Use database: %s", dbname));
- if (!empty_is_ok || (dbname && db_length))
- {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (! no_access_check)
- {
- if (test_all_bits(thd->master_access,DB_ACLS))
- db_access=DB_ACLS;
- else
- db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
- thd->master_access);
- if (!(db_access & DB_ACLS) &&
- (!grant_option || check_grant_db(thd,dbname)))
- {
- net_printf(thd,ER_DBACCESS_DENIED_ERROR,
- thd->priv_user,
- thd->priv_host,
- dbname);
- mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
- thd->priv_user,
- thd->priv_host,
- dbname);
- my_free(dbname,MYF(0));
- DBUG_RETURN(1);
- }
- }
+ if (test_all_bits(thd->master_access,DB_ACLS))
+ db_access=DB_ACLS;
+ else
+ db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
+ thd->master_access);
+ if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
+ {
+ net_printf(thd,ER_DBACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->priv_host,
+ dbname);
+ mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
+ thd->priv_user,
+ thd->priv_host,
+ dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
+ }
#endif
- (void) sprintf(path,"%s/%s",mysql_data_home,dbname);
- length=unpack_dirname(path,path); // Convert if not unix
- if (length && path[length-1] == FN_LIBCHAR)
- path[length-1]=0; // remove ending '\'
- if (access(path,F_OK))
- {
- net_printf(thd,ER_BAD_DB_ERROR,dbname);
- my_free(dbname,MYF(0));
- DBUG_RETURN(1);
- }
+ (void) sprintf(path,"%s/%s",mysql_data_home,dbname);
+ length=unpack_dirname(path,path); // Convert if not unix
+ if (length && path[length-1] == FN_LIBCHAR)
+ path[length-1]=0; // remove ending '\'
+ if (access(path,F_OK))
+ {
+ net_printf(thd,ER_BAD_DB_ERROR,dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
}
send_ok(thd);
x_free(thd->db);
thd->db=dbname; // THD::~THD will free this
thd->db_length=db_length;
- if (!empty_is_ok || (dbname && db_length))
- {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (! no_access_check)
- thd->db_access=db_access;
+ thd->db_access=db_access;
#endif
- strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
- load_db_opt(thd, path, &create);
- thd->db_charset= create.default_table_charset ?
- create.default_table_charset :
- thd->variables.collation_server;
- thd->variables.collation_database= thd->db_charset;
- }
+ strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
+ load_db_opt(thd, path, &create);
+ thd->db_charset= create.default_table_charset ?
+ create.default_table_charset :
+ thd->variables.collation_server;
+ thd->variables.collation_database= thd->db_charset;
DBUG_RETURN(0);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 50f475eb68c..d2f7e73b2b8 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -3923,83 +3923,90 @@ simple_expr:
{ $$= new Item_func_round($3,$5,1); }
| TRUE_SYM
{ $$= new Item_int((char*) "TRUE",1,1); }
- | IDENT_sys '(' udf_expr_list ')'
+ | ident '.' ident '(' udf_expr_list ')'
{
- sp_name *name= sp_name_current_db_new(YYTHD, $1);
-
- if (sp_function_exists(YYTHD, name))
- {
- LEX *lex= Lex;
+ LEX *lex= Lex;
+ sp_name *name= new sp_name($1, $3);
- sp_add_fun_to_lex(lex, name);
- if ($3)
- $$= new Item_func_sp(name, *$3);
- else
- $$= new Item_func_sp(name);
- }
+ name->init_qname(YYTHD);
+ sp_add_fun_to_lex(Lex, name);
+ if ($5)
+ $$= new Item_func_sp(name, *$5);
else
- {
+ $$= new Item_func_sp(name);
+ }
+ | IDENT_sys '(' udf_expr_list ')'
+ {
#ifdef HAVE_DLOPEN
- udf_func *udf;
+ udf_func *udf;
- if (using_udf_functions && (udf=find_udf($1.str, $1.length)))
- {
- switch (udf->returns) {
- case STRING_RESULT:
- if (udf->type == UDFTYPE_FUNCTION)
- {
- if ($3 != NULL)
- $$ = new Item_func_udf_str(udf, *$3);
- else
- $$ = new Item_func_udf_str(udf);
- }
- else
- {
- if ($3 != NULL)
- $$ = new Item_sum_udf_str(udf, *$3);
- else
- $$ = new Item_sum_udf_str(udf);
- }
- break;
- case REAL_RESULT:
- if (udf->type == UDFTYPE_FUNCTION)
- {
- if ($3 != NULL)
- $$ = new Item_func_udf_float(udf, *$3);
- else
- $$ = new Item_func_udf_float(udf);
- }
- else
- {
- if ($3 != NULL)
- $$ = new Item_sum_udf_float(udf, *$3);
- else
- $$ = new Item_sum_udf_float(udf);
- }
- break;
- case INT_RESULT:
- if (udf->type == UDFTYPE_FUNCTION)
- {
- if ($3 != NULL)
- $$ = new Item_func_udf_int(udf, *$3);
- else
- $$ = new Item_func_udf_int(udf);
- }
- else
- {
- if ($3 != NULL)
- $$ = new Item_sum_udf_int(udf, *$3);
- else
- $$ = new Item_sum_udf_int(udf);
- }
- break;
- default:
- YYABORT;
- }
- }
+ if (using_udf_functions && (udf=find_udf($1.str, $1.length)))
+ {
+ switch (udf->returns) {
+ case STRING_RESULT:
+ if (udf->type == UDFTYPE_FUNCTION)
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_str(udf, *$3);
+ else
+ $$ = new Item_func_udf_str(udf);
+ }
+ else
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_str(udf, *$3);
+ else
+ $$ = new Item_sum_udf_str(udf);
+ }
+ break;
+ case REAL_RESULT:
+ if (udf->type == UDFTYPE_FUNCTION)
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_float(udf, *$3);
+ else
+ $$ = new Item_func_udf_float(udf);
+ }
+ else
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_float(udf, *$3);
+ else
+ $$ = new Item_sum_udf_float(udf);
+ }
+ break;
+ case INT_RESULT:
+ if (udf->type == UDFTYPE_FUNCTION)
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_int(udf, *$3);
+ else
+ $$ = new Item_func_udf_int(udf);
+ }
+ else
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_int(udf, *$3);
+ else
+ $$ = new Item_sum_udf_int(udf);
+ }
+ break;
+ default:
+ YYABORT;
+ }
+ }
+ else
#endif /* HAVE_DLOPEN */
+ {
+ sp_name *name= sp_name_current_db_new(YYTHD, $1);
+
+ sp_add_fun_to_lex(Lex, name);
+ if ($3)
+ $$= new Item_func_sp(name, *$3);
+ else
+ $$= new Item_func_sp(name);
}
- }
+ }
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
{
$$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);