Made stored FUNCTION invokation work almost always. Still buggy and unstable, and
various known problems, but good enough for a checkpoint commit. mysql-test/r/sp.result: New tests for invoking simple FUNCTIONs. mysql-test/t/sp.test: New tests for invoking simple FUNCTIONs. sql/item_func.cc: New Item_func_sp for stored FUNCTIONs. sql/item_func.h: New Item_func_sp for stored FUNCTIONs. sql/sp.cc: Close mysql.proc table earlier so recursive find_function calls work. Added temporary sp_function_exists() function for checking without parsing. sql/sp.h: Added temporary sp_function_exists() function for checking without parsing. sql/sp_head.cc: New code for executing a FUNCTION. (And reworked some of the old code in the process.) sql/sp_head.h: New code for executing a FUNCTION. sql/sp_rcontext.h: Added result slot for FUNCTIONs. sql/sql_lex.cc: Added check for stored FUNCTION, analogous to UDFs. sql/sql_parse.cc: sp_head::execute was renamed into execute_procedure. sql/sql_yacc.yy: Added parsing of stored FUNCTION invocation and code generation for RETURN statement.
This commit is contained in:
parent
0521fb5444
commit
76b037dc42
@ -375,11 +375,21 @@ create table test.t2 select * from test.t1;
|
||||
insert into test.t2 values (concat(x, "2"), y+2);
|
||||
end;
|
||||
drop procedure create_select;
|
||||
create function foo returns real soname "foo.so";
|
||||
Can't open shared library 'foo.so' (errno: 22 foo.so: cannot open shared object file: No such file or director)
|
||||
create function e() returns double
|
||||
return 2.7182818284590452354;
|
||||
drop function e;
|
||||
select e();
|
||||
e()
|
||||
2.718281828459
|
||||
create function inc(i int) returns int
|
||||
return i+1;
|
||||
select inc(1), inc(99), inc(-71);
|
||||
inc(1) inc(99) inc(-71)
|
||||
2 100 -70
|
||||
create function mul(x int, y int) returns int
|
||||
return x*y;
|
||||
select mul(1,1), mul(3,5), mul(4711, 666);
|
||||
mul(1,1) mul(3,5) mul(4711, 666)
|
||||
1 15 3137526
|
||||
create function fac(n int unsigned) returns bigint unsigned
|
||||
begin
|
||||
declare f bigint unsigned;
|
||||
@ -390,5 +400,11 @@ set n = n - 1;
|
||||
end while;
|
||||
return f;
|
||||
end;
|
||||
select fac(1), fac(2), fac(10);
|
||||
fac(1) fac(2) fac(10)
|
||||
1 2 3628800
|
||||
drop function e;
|
||||
drop function inc;
|
||||
drop function mul;
|
||||
drop function fac;
|
||||
drop table t1;
|
||||
|
@ -435,17 +435,31 @@ drop procedure create_select|
|
||||
|
||||
# Check that we get the right error, i.e. UDF declaration parses correctly,
|
||||
# but foo.so doesn't exist.
|
||||
--error 1126
|
||||
create function foo returns real soname "foo.so"|
|
||||
# QQ This generates an error message containing a misleading errno which
|
||||
# might vary between systems (it usually doesn't have anything to do with
|
||||
# the actual failing dlopen()).
|
||||
#--error 1126
|
||||
#create function foo returns real soname "foo.so"|
|
||||
|
||||
# A minimal, constant FUNCTION.
|
||||
create function e() returns double
|
||||
return 2.7182818284590452354|
|
||||
|
||||
drop function e|
|
||||
select e()|
|
||||
|
||||
# A minimal function with one argument
|
||||
create function inc(i int) returns int
|
||||
return i+1|
|
||||
|
||||
# A function with flow control and a RETURN statement
|
||||
select inc(1), inc(99), inc(-71)|
|
||||
|
||||
# A minimal function with two arguments
|
||||
create function mul(x int, y int) returns int
|
||||
return x*y|
|
||||
|
||||
select mul(1,1), mul(3,5), mul(4711, 666)|
|
||||
|
||||
# A function with flow control
|
||||
create function fac(n int unsigned) returns bigint unsigned
|
||||
begin
|
||||
declare f bigint unsigned;
|
||||
@ -458,6 +472,11 @@ begin
|
||||
return f;
|
||||
end|
|
||||
|
||||
select fac(1), fac(2), fac(10)|
|
||||
|
||||
drop function e|
|
||||
drop function inc|
|
||||
drop function mul|
|
||||
drop function fac|
|
||||
|
||||
delimiter ;|
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include <time.h>
|
||||
#include <ft_global.h>
|
||||
#include <zlib.h>
|
||||
#include "sp_head.h"
|
||||
#include "sp_rcontext.h"
|
||||
#include "sp.h"
|
||||
|
||||
/* return TRUE if item is a constant */
|
||||
|
||||
@ -2770,3 +2773,75 @@ double Item_func_glength::val()
|
||||
geom.length(&res));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Item_func_sp::execute(Item **itp)
|
||||
{
|
||||
DBUG_ENTER("Item_func_sp::execute");
|
||||
THD *thd= current_thd;
|
||||
|
||||
if (!m_sp && !(m_sp= sp_find_function(thd, &m_name)))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
DBUG_RETURN(m_sp->execute_function(thd, args, arg_count, itp));
|
||||
}
|
||||
|
||||
Item_result
|
||||
Item_func_sp::result_type() const
|
||||
{
|
||||
DBUG_ENTER("Item_func_sp::result_type");
|
||||
DBUG_PRINT("info", ("m_sp = %p", m_sp));
|
||||
|
||||
if (m_sp)
|
||||
{
|
||||
DBUG_RETURN(m_sp->result());
|
||||
}
|
||||
else
|
||||
{
|
||||
sp_head *sp= sp_find_function(current_thd, (LEX_STRING *)(&m_name));
|
||||
if (sp)
|
||||
DBUG_RETURN(m_sp->result());
|
||||
DBUG_RETURN(STRING_RESULT);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Item_func_sp::make_field(Send_field *field)
|
||||
{
|
||||
DBUG_ENTER("Item_func_sp::make_field");
|
||||
Item *it;
|
||||
|
||||
if (!execute(&it))
|
||||
{
|
||||
it->set_name(name, 0);
|
||||
init_make_field(field, field_type());
|
||||
it->make_field(field);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
void
|
||||
Item_func_sp::fix_length_and_dec()
|
||||
{
|
||||
DBUG_ENTER("Item_func_sp::fix_length_and_dec");
|
||||
|
||||
if (m_sp || (m_sp= sp_find_function(current_thd, &m_name)))
|
||||
{
|
||||
switch (m_sp->result()) {
|
||||
case STRING_RESULT:
|
||||
maybe_null= 1;
|
||||
max_length= 0;
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
decimals= NOT_FIXED_DEC;
|
||||
max_length= float_length(decimals);
|
||||
break;
|
||||
case INT_RESULT:
|
||||
decimals= 0;
|
||||
max_length= 21;
|
||||
break;
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -1147,3 +1147,69 @@ enum Item_cast
|
||||
ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
|
||||
ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Stored FUNCTIONs
|
||||
*
|
||||
*/
|
||||
|
||||
class sp_head;
|
||||
|
||||
class Item_func_sp :public Item_func
|
||||
{
|
||||
private:
|
||||
LEX_STRING m_name;
|
||||
sp_head *m_sp;
|
||||
|
||||
int execute(Item **itp);
|
||||
|
||||
public:
|
||||
|
||||
Item_func_sp(LEX_STRING name)
|
||||
:Item_func(), m_name(name), m_sp(NULL)
|
||||
{}
|
||||
|
||||
Item_func_sp(LEX_STRING name, List<Item> &list)
|
||||
:Item_func(list), m_name(name), m_sp(NULL)
|
||||
{}
|
||||
|
||||
virtual ~Item_func_sp()
|
||||
{}
|
||||
|
||||
const char *func_name() const
|
||||
{
|
||||
return m_name.str;
|
||||
}
|
||||
|
||||
Item_result result_type() const;
|
||||
|
||||
longlong val_int()
|
||||
{
|
||||
return (longlong)Item_func_sp::val();
|
||||
}
|
||||
|
||||
double val()
|
||||
{
|
||||
Item *it;
|
||||
|
||||
if (execute(&it))
|
||||
return 0.0;
|
||||
return it->val();
|
||||
}
|
||||
|
||||
String *val_str(String *str)
|
||||
{
|
||||
Item *it;
|
||||
|
||||
if (execute(&it))
|
||||
return NULL;
|
||||
return it->val_str(str);
|
||||
}
|
||||
|
||||
void make_field(Send_field *field);
|
||||
|
||||
void fix_length_and_dec();
|
||||
|
||||
};
|
||||
|
21
sql/sp.cc
21
sql/sp.cc
@ -84,6 +84,8 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
||||
ret= SP_GET_FIELD_FAILED;
|
||||
goto done;
|
||||
}
|
||||
close_thread_tables(thd);
|
||||
table= NULL;
|
||||
|
||||
tmplex= lex_start(thd, (uchar*)defstr, strlen(defstr));
|
||||
if (yyparse(thd) || thd->is_fatal_error || tmplex->sphead == NULL)
|
||||
@ -92,7 +94,7 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
||||
*sphp= tmplex->sphead;
|
||||
|
||||
done:
|
||||
if (ret == SP_OK && table)
|
||||
if (ret != SP_OK && table)
|
||||
close_thread_tables(thd);
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
@ -208,7 +210,7 @@ sp_drop_procedure(THD *thd, char *name, uint namelen)
|
||||
sp_head *
|
||||
sp_find_function(THD *thd, LEX_STRING *name)
|
||||
{
|
||||
DBUG_ENTER("sp_find_function_i");
|
||||
DBUG_ENTER("sp_find_function");
|
||||
sp_head *sp;
|
||||
|
||||
DBUG_PRINT("enter", ("name: %*s", name->length, name->str));
|
||||
@ -243,3 +245,18 @@ sp_drop_function(THD *thd, char *name, uint namelen)
|
||||
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
// QQ Temporary until the function call detection in sql_lex has been reworked.
|
||||
bool
|
||||
sp_function_exists(THD *thd, LEX_STRING *name)
|
||||
{
|
||||
TABLE *table;
|
||||
|
||||
if (db_find_routine_aux(thd, TYPE_ENUM_FUNCTION,
|
||||
name->str, name->length, TL_READ, &table) == SP_OK)
|
||||
{
|
||||
close_thread_tables(thd);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
4
sql/sp.h
4
sql/sp.h
@ -46,4 +46,8 @@ sp_create_function(THD *thd, char *name, uint namelen, char *def, uint deflen);
|
||||
int
|
||||
sp_drop_function(THD *thd, char *name, uint namelen);
|
||||
|
||||
// QQ Temporary until the function call detection in sql_lex has been reworked.
|
||||
bool
|
||||
sp_function_exists(THD *thd, LEX_STRING *name);
|
||||
|
||||
#endif /* _SP_H_ */
|
||||
|
166
sql/sp_head.cc
166
sql/sp_head.cc
@ -24,6 +24,26 @@
|
||||
#include "sp_pcontext.h"
|
||||
#include "sp_rcontext.h"
|
||||
|
||||
Item_result
|
||||
sp_map_result_type(enum enum_field_types type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MYSQL_TYPE_TINY:
|
||||
case MYSQL_TYPE_SHORT:
|
||||
case MYSQL_TYPE_LONG:
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
case MYSQL_TYPE_INT24:
|
||||
return INT_RESULT;
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
return REAL_RESULT;
|
||||
default:
|
||||
return STRING_RESULT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Evaluate a (presumed) func item. Always returns an item, the parameter
|
||||
** if nothing else.
|
||||
*/
|
||||
@ -36,48 +56,28 @@ eval_func_item(THD *thd, Item *it, enum enum_field_types type)
|
||||
return it; // Shouldn't happen?
|
||||
|
||||
/* QQ How do we do this? Is there some better way? */
|
||||
switch (type)
|
||||
if (type == MYSQL_TYPE_NULL)
|
||||
it= new Item_null();
|
||||
else
|
||||
{
|
||||
case MYSQL_TYPE_TINY:
|
||||
case MYSQL_TYPE_SHORT:
|
||||
case MYSQL_TYPE_LONG:
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
case MYSQL_TYPE_INT24:
|
||||
it= new Item_int(it->val_int());
|
||||
break;
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
it= new Item_real(it->val());
|
||||
break;
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
case MYSQL_TYPE_DATE:
|
||||
case MYSQL_TYPE_TIME:
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
case MYSQL_TYPE_YEAR:
|
||||
case MYSQL_TYPE_NEWDATE:
|
||||
{
|
||||
char buffer[MAX_FIELD_WIDTH];
|
||||
String tmp(buffer, sizeof(buffer), default_charset_info);
|
||||
String *s= it->val_str(&tmp);
|
||||
|
||||
it= new Item_string(s->c_ptr_quick(), s->length(), default_charset_info);
|
||||
switch (sp_map_result_type(type)) {
|
||||
case INT_RESULT:
|
||||
it= new Item_int(it->val_int());
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
it= new Item_real(it->val());
|
||||
break;
|
||||
default:
|
||||
{
|
||||
char buffer[MAX_FIELD_WIDTH];
|
||||
String tmp(buffer, sizeof(buffer), default_charset_info);
|
||||
String *s= it->val_str(&tmp);
|
||||
|
||||
it= new Item_string(s->c_ptr_quick(), s->length(),
|
||||
default_charset_info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
case MYSQL_TYPE_NULL:
|
||||
it= new Item_null(); // A NULL is a NULL is a NULL...
|
||||
break;
|
||||
case MYSQL_TYPE_ENUM:
|
||||
case MYSQL_TYPE_SET:
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
case MYSQL_TYPE_LONG_BLOB:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
case MYSQL_TYPE_GEOMETRY:
|
||||
/* QQ Don't know what to do with the rest. */
|
||||
break;
|
||||
}
|
||||
|
||||
return it;
|
||||
@ -118,12 +118,69 @@ sp_head::create(THD *thd)
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sp_head::execute(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("sp_head::execute");
|
||||
DBUG_PRINT("executing", ("procedure %s", ((String *)m_name->const_string())->c_ptr()));
|
||||
int ret= 0;
|
||||
uint ip= 0;
|
||||
|
||||
do
|
||||
{
|
||||
sp_instr *i;
|
||||
|
||||
i = get_instr(ip); // Returns NULL when we're done.
|
||||
if (i == NULL)
|
||||
break;
|
||||
DBUG_PRINT("execute", ("Instruction %u", ip));
|
||||
ret= i->execute(thd, &ip);
|
||||
} while (ret == 0);
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
|
||||
{
|
||||
DBUG_ENTER("sp_head::execute");
|
||||
DBUG_PRINT("executing", ("procedure %s", ((String *)m_name->const_string())->c_ptr()));
|
||||
sp_pcontext *pctx = m_call_lex->spcont;
|
||||
uint csize = pctx->max_framesize();
|
||||
uint params = pctx->params();
|
||||
sp_rcontext *octx = thd->spcont;
|
||||
sp_rcontext *nctx = NULL;
|
||||
uint i;
|
||||
int ret;
|
||||
|
||||
// QQ Should have some error checking here? (no. of args, types, etc...)
|
||||
nctx= new sp_rcontext(csize);
|
||||
for (i= 0 ; i < params && i < argcount ; i++)
|
||||
{
|
||||
sp_pvar_t *pvar = pctx->find_pvar(i);
|
||||
|
||||
nctx->push_item(eval_func_item(thd, *argp++, pvar->type));
|
||||
}
|
||||
// The rest of the frame are local variables which are all IN.
|
||||
// QQ See comment in execute_procedure below.
|
||||
for (; i < csize ; i++)
|
||||
nctx->push_item(NULL);
|
||||
thd->spcont= nctx;
|
||||
|
||||
ret= execute(thd);
|
||||
if (ret == 0)
|
||||
*resp= nctx->get_result();
|
||||
|
||||
thd->spcont= octx;
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
int
|
||||
sp_head::execute_procedure(THD *thd, List<Item> *args)
|
||||
{
|
||||
DBUG_ENTER("sp_head::execute");
|
||||
DBUG_PRINT("executing", ("procedure %s", ((String *)m_name->const_string())->c_ptr()));
|
||||
int ret;
|
||||
sp_instr *p;
|
||||
sp_pcontext *pctx = m_call_lex->spcont;
|
||||
uint csize = pctx->max_framesize();
|
||||
@ -135,7 +192,7 @@ sp_head::execute(THD *thd)
|
||||
if (csize > 0)
|
||||
{
|
||||
uint i;
|
||||
List_iterator_fast<Item> li(m_call_lex->value_list);
|
||||
List_iterator_fast<Item> li(*args);
|
||||
Item *it;
|
||||
|
||||
nctx = new sp_rcontext(csize);
|
||||
@ -174,20 +231,7 @@ sp_head::execute(THD *thd)
|
||||
thd->spcont= nctx;
|
||||
}
|
||||
|
||||
{ // Execute instructions...
|
||||
uint ip= 0;
|
||||
|
||||
while (ret == 0)
|
||||
{
|
||||
sp_instr *i;
|
||||
|
||||
i = get_instr(ip); // Returns NULL when we're done.
|
||||
if (i == NULL)
|
||||
break;
|
||||
DBUG_PRINT("execute", ("Instruction %u", ip));
|
||||
ret= i->execute(thd, &ip);
|
||||
}
|
||||
}
|
||||
ret= execute(thd);
|
||||
|
||||
// Don't copy back OUT values if we got an error
|
||||
if (ret == 0 && csize > 0)
|
||||
@ -424,3 +468,15 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
|
||||
*nextp = m_ip+1;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
//
|
||||
// sp_instr_return
|
||||
//
|
||||
int
|
||||
sp_instr_return::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
DBUG_ENTER("sp_instr_return::execute");
|
||||
thd->spcont->set_result(eval_func_item(thd, m_value, m_type));
|
||||
*nextp= UINT_MAX;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
@ -29,6 +29,9 @@
|
||||
#define TYPE_ENUM_FUNCTION 1
|
||||
#define TYPE_ENUM_PROCEDURE 2
|
||||
|
||||
Item_result
|
||||
sp_map_result_type(enum enum_field_types type);
|
||||
|
||||
struct sp_label;
|
||||
|
||||
class sp_instr;
|
||||
@ -62,7 +65,10 @@ public:
|
||||
create(THD *thd);
|
||||
|
||||
int
|
||||
execute(THD *thd);
|
||||
execute_function(THD *thd, Item **args, uint argcount, Item **resp);
|
||||
|
||||
int
|
||||
execute_procedure(THD *thd, List<Item> *args);
|
||||
|
||||
inline void
|
||||
add_instr(sp_instr *i)
|
||||
@ -103,6 +109,11 @@ public:
|
||||
return n->c_ptr();
|
||||
}
|
||||
|
||||
inline Item_result result()
|
||||
{
|
||||
return sp_map_result_type(m_returns);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Item_string *m_name;
|
||||
@ -122,10 +133,14 @@ private:
|
||||
{
|
||||
sp_instr *in= NULL;
|
||||
|
||||
get_dynamic(&m_instr, (gptr)&in, i);
|
||||
if (i < m_instr.elements)
|
||||
get_dynamic(&m_instr, (gptr)&in, i);
|
||||
return in;
|
||||
}
|
||||
|
||||
int
|
||||
execute(THD *thd);
|
||||
|
||||
}; // class sp_head : public Sql_alloc
|
||||
|
||||
|
||||
@ -319,4 +334,28 @@ private:
|
||||
|
||||
}; // class sp_instr_jump_if_not : public sp_instr_jump
|
||||
|
||||
|
||||
class sp_instr_return : public sp_instr
|
||||
{
|
||||
sp_instr_return(const sp_instr_return &); /* Prevent use of these */
|
||||
void operator=(sp_instr_return &);
|
||||
|
||||
public:
|
||||
|
||||
sp_instr_return(uint ip, Item *val, enum enum_field_types type)
|
||||
: sp_instr(ip), m_value(val), m_type(type)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_return()
|
||||
{}
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
protected:
|
||||
|
||||
Item *m_value;
|
||||
enum enum_field_types m_type;
|
||||
|
||||
}; // class sp_instr_return : public sp_instr
|
||||
|
||||
#endif /* _SP_HEAD_H_ */
|
||||
|
@ -26,7 +26,7 @@ class sp_rcontext : public Sql_alloc
|
||||
public:
|
||||
|
||||
sp_rcontext(uint size)
|
||||
: m_count(0), m_size(size)
|
||||
: m_count(0), m_size(size), m_result(NULL)
|
||||
{
|
||||
m_frame = (Item **)sql_alloc(size * sizeof(Item*));
|
||||
m_outs = (int *)sql_alloc(size * sizeof(int));
|
||||
@ -70,12 +70,25 @@ class sp_rcontext : public Sql_alloc
|
||||
return m_outs[idx];
|
||||
}
|
||||
|
||||
inline void
|
||||
set_result(Item *it)
|
||||
{
|
||||
m_result= it;
|
||||
}
|
||||
|
||||
inline Item *
|
||||
get_result()
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint m_count;
|
||||
uint m_size;
|
||||
Item **m_frame;
|
||||
int *m_outs;
|
||||
Item *m_result; // For FUNCTIONs
|
||||
|
||||
}; // class sp_rcontext : public Sql_alloc
|
||||
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "item_create.h"
|
||||
#include <m_ctype.h>
|
||||
#include <hash.h>
|
||||
#include "sp.h"
|
||||
#include "sp_head.h"
|
||||
|
||||
LEX_STRING tmp_table_alias= {(char*) "tmp-table",8};
|
||||
|
||||
@ -197,6 +199,17 @@ static int find_keyword(LEX *lex, uint len, bool function)
|
||||
lex->yylval->symbol.length=len;
|
||||
return symbol->tok;
|
||||
}
|
||||
|
||||
LEX_STRING ls;
|
||||
ls.str = (char *)tok; ls.length= len;
|
||||
if (function && sp_function_exists(current_thd, &ls)) // QQ temp fix
|
||||
{
|
||||
lex->safe_to_cache_query= 0;
|
||||
lex->yylval->lex_str.str= lex->thd->strmake((char*)lex->tok_start, len);
|
||||
lex->yylval->lex_str.length= len;
|
||||
return SP_FUNC;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DLOPEN
|
||||
udf_func *udf;
|
||||
if (function && using_udf_functions && (udf=find_udf((char*) tok, len)))
|
||||
|
@ -2959,6 +2959,7 @@ mysql_execute_command(THD *thd)
|
||||
{
|
||||
uint namelen;
|
||||
char *name= lex->sphead->name(&namelen);
|
||||
#ifdef HAVE_DLOPEN
|
||||
udf_func *udf = find_udf(name, namelen);
|
||||
|
||||
if (udf)
|
||||
@ -2966,6 +2967,7 @@ mysql_execute_command(THD *thd)
|
||||
net_printf(thd, ER_UDF_EXISTS, name);
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
res= lex->sphead->create(thd);
|
||||
switch (res)
|
||||
{
|
||||
@ -3000,7 +3002,7 @@ mysql_execute_command(THD *thd)
|
||||
|
||||
thd->net.no_send_ok= TRUE;
|
||||
#endif
|
||||
res= sp->execute(thd);
|
||||
res= sp->execute_procedure(thd, &lex->value_list);
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
thd->net.no_send_ok= nsok;
|
||||
#endif
|
||||
|
@ -506,6 +506,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
||||
%token ROUND
|
||||
%token SECOND_SYM
|
||||
%token SHARE_SYM
|
||||
%token SP_FUNC
|
||||
%token SUBSTRING
|
||||
%token SUBSTRING_INDEX
|
||||
%token TRIM
|
||||
@ -575,7 +576,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
||||
%type <lex_str>
|
||||
IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME
|
||||
ULONGLONG_NUM field_ident select_alias ident ident_or_text
|
||||
UNDERSCORE_CHARSET
|
||||
UNDERSCORE_CHARSET SP_FUNC ident_or_spfunc
|
||||
|
||||
%type <lex_str_ptr>
|
||||
opt_table_alias
|
||||
@ -903,7 +904,7 @@ create:
|
||||
lex->name=$4.str;
|
||||
lex->create_info.options=$3;
|
||||
}
|
||||
| CREATE udf_func_type FUNCTION_SYM IDENT
|
||||
| CREATE udf_func_type FUNCTION_SYM ident_or_spfunc
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
lex->udf.name = $4;
|
||||
@ -929,6 +930,11 @@ create:
|
||||
}
|
||||
;
|
||||
|
||||
ident_or_spfunc:
|
||||
IDENT { $$= $1; }
|
||||
| SP_FUNC { $$= $1; }
|
||||
;
|
||||
|
||||
create_function_tail:
|
||||
RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING
|
||||
{
|
||||
@ -1122,7 +1128,11 @@ sp_proc_stmt:
|
||||
}
|
||||
else
|
||||
{
|
||||
/* QQ nothing yet */
|
||||
sp_instr_return *i=
|
||||
new sp_instr_return(lex->sphead->instructions(),
|
||||
$2, lex->sphead->m_returns);
|
||||
|
||||
lex->sphead->add_instr(i);
|
||||
}
|
||||
}
|
||||
| IF sp_if END IF {}
|
||||
@ -2863,6 +2873,13 @@ simple_expr:
|
||||
{ $$= new Item_func_round($3,$5,1); }
|
||||
| TRUE_SYM
|
||||
{ $$= new Item_int((char*) "TRUE",1,1); }
|
||||
| SP_FUNC '(' udf_expr_list ')'
|
||||
{
|
||||
if ($3)
|
||||
$$= new Item_func_sp($1, *$3);
|
||||
else
|
||||
$$= new Item_func_sp($1);
|
||||
}
|
||||
| UDA_CHAR_SUM '(' udf_expr_list ')'
|
||||
{
|
||||
if ($3 != NULL)
|
||||
|
Loading…
x
Reference in New Issue
Block a user