Commit aae07a4d authored by pem@mysql.com's avatar pem@mysql.com

Simplistic, experimental framework for Stored Procedures (SPs).

Implements creation and dropping of PROCEDUREs, IN, OUT, and INOUT parameters,
single-statement procedures, rudimentary multi-statement (begin-end) prodedures
(when the client can handle it), and local variables.
Missing most of the embedded SQL language, all attributes, FUNCTIONs, error handling,
reparses procedures at each call (no caching), etc, etc.
Certainly buggy too, but procedures can actually be created and called....
parent 60934fb0
...@@ -57,7 +57,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ ...@@ -57,7 +57,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
lex.h lex_symbol.h sql_acl.h sql_crypt.h \ lex.h lex_symbol.h sql_acl.h sql_crypt.h \
log_event.h mini_client.h sql_repl.h slave.h \ log_event.h mini_client.h sql_repl.h slave.h \
stacktrace.h sql_sort.h sql_cache.h set_var.h \ stacktrace.h sql_sort.h sql_cache.h set_var.h \
spatial.h gstream.h spatial.h gstream.h sp_head.h sp_pcontext.h \
sp_rcontext.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc \ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
...@@ -85,7 +86,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ ...@@ -85,7 +86,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
slave.cc sql_repl.cc sql_union.cc sql_derived.cc \ slave.cc sql_repl.cc sql_union.cc sql_derived.cc \
mini_client.cc mini_client_errors.c \ mini_client.cc mini_client_errors.c \
stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\ stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\
gstream.cc spatial.cc sql_help.cc gstream.cc spatial.cc sql_help.cc \
sp_head.cc sp_pcontext.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS) gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#include <m_ctype.h> #include <m_ctype.h>
#include "my_dir.h" #include "my_dir.h"
#include "sp_rcontext.h"
/***************************************************************************** /*****************************************************************************
** Item functions ** Item functions
...@@ -147,6 +148,24 @@ CHARSET_INFO * Item::thd_charset() const ...@@ -147,6 +148,24 @@ CHARSET_INFO * Item::thd_charset() const
return current_thd->thd_charset; return current_thd->thd_charset;
} }
Item *
Item_splocal::this_item()
{
THD *thd= current_thd;
return thd->spcont->get_item(m_offset);
}
Item *
Item_splocal::this_const_item() const
{
THD *thd= current_thd;
return thd->spcont->get_item(m_offset);
}
Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name) Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name)
{ {
set_field(f); set_field(f);
......
...@@ -94,6 +94,8 @@ class Item { ...@@ -94,6 +94,8 @@ class Item {
CHARSET_INFO *thd_charset() const; CHARSET_INFO *thd_charset() const;
CHARSET_INFO *charset() const { return str_value.charset(); }; CHARSET_INFO *charset() const { return str_value.charset(); };
void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); } void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); }
virtual Item *this_item() { return this; } /* For SPs mostly. */
virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */
// Row emulation // Row emulation
virtual uint cols() { return 1; } virtual uint cols() { return 1; }
...@@ -103,6 +105,57 @@ class Item { ...@@ -103,6 +105,57 @@ class Item {
}; };
// A local SP variable (incl. parameters), used in runtime
class Item_splocal : public Item
{
private:
uint m_offset;
public:
Item_splocal(uint offset)
: m_offset(offset)
{}
Item *this_item();
Item *this_const_item() const;
inline uint get_offset()
{
return m_offset;
}
// Abstract methods inherited from Item. Just defer the call to
// the item in the frame
inline enum Type type() const
{
return this_const_item()->type();
}
inline double val()
{
return this_item()->val();
}
inline longlong val_int()
{
return this_item()->val_int();
}
inline String *val_str(String *sp)
{
return this_item()->val_str(sp);
}
inline void make_field(Send_field *field)
{
this_item()->make_field(field);
}
};
/* /*
Wrapper base class Wrapper base class
*/ */
......
...@@ -79,6 +79,7 @@ static SYMBOL symbols[] = { ...@@ -79,6 +79,7 @@ static SYMBOL symbols[] = {
{ "BY", SYM(BY),0,0}, { "BY", SYM(BY),0,0},
{ "BYTE", SYM(BYTE_SYM), 0, 0}, { "BYTE", SYM(BYTE_SYM), 0, 0},
{ "CACHE", SYM(CACHE_SYM),0,0}, { "CACHE", SYM(CACHE_SYM),0,0},
{ "CALL", SYM(CALL_SYM),0,0},
{ "CASCADE", SYM(CASCADE),0,0}, { "CASCADE", SYM(CASCADE),0,0},
{ "CASE", SYM(CASE_SYM),0,0}, { "CASE", SYM(CASE_SYM),0,0},
{ "CHAR", SYM(CHAR_SYM),0,0}, { "CHAR", SYM(CHAR_SYM),0,0},
...@@ -117,6 +118,7 @@ static SYMBOL symbols[] = { ...@@ -117,6 +118,7 @@ static SYMBOL symbols[] = {
{ "DAY_SECOND", SYM(DAY_SECOND_SYM),0,0}, { "DAY_SECOND", SYM(DAY_SECOND_SYM),0,0},
{ "DEC", SYM(DECIMAL_SYM),0,0}, { "DEC", SYM(DECIMAL_SYM),0,0},
{ "DECIMAL", SYM(DECIMAL_SYM),0,0}, { "DECIMAL", SYM(DECIMAL_SYM),0,0},
{ "DECLARE", SYM(DECLARE_SYM),0,0},
{ "DES_KEY_FILE", SYM(DES_KEY_FILE),0,0}, { "DES_KEY_FILE", SYM(DES_KEY_FILE),0,0},
{ "DEFAULT", SYM(DEFAULT),0,0}, { "DEFAULT", SYM(DEFAULT),0,0},
{ "DELAYED", SYM(DELAYED_SYM),0,0}, { "DELAYED", SYM(DELAYED_SYM),0,0},
...@@ -193,6 +195,7 @@ static SYMBOL symbols[] = { ...@@ -193,6 +195,7 @@ static SYMBOL symbols[] = {
{ "INNER", SYM(INNER_SYM),0,0}, { "INNER", SYM(INNER_SYM),0,0},
{ "INNOBASE", SYM(INNOBASE_SYM),0,0}, { "INNOBASE", SYM(INNOBASE_SYM),0,0},
{ "INNODB", SYM(INNOBASE_SYM),0,0}, { "INNODB", SYM(INNOBASE_SYM),0,0},
{ "INOUT", SYM(INOUT_SYM),0,0},
{ "INSERT", SYM(INSERT),0,0}, { "INSERT", SYM(INSERT),0,0},
{ "INSERT_METHOD", SYM(INSERT_METHOD),0,0}, { "INSERT_METHOD", SYM(INSERT_METHOD),0,0},
{ "INT", SYM(INT_SYM),0,0}, { "INT", SYM(INT_SYM),0,0},
...@@ -279,6 +282,7 @@ static SYMBOL symbols[] = { ...@@ -279,6 +282,7 @@ static SYMBOL symbols[] = {
{ "OPTIONALLY", SYM(OPTIONALLY),0,0}, { "OPTIONALLY", SYM(OPTIONALLY),0,0},
{ "OR", SYM(OR),0,0}, { "OR", SYM(OR),0,0},
{ "ORDER", SYM(ORDER_SYM),0,0}, { "ORDER", SYM(ORDER_SYM),0,0},
{ "OUT", SYM(OUT_SYM),0,0},
{ "OUTER", SYM(OUTER),0,0}, { "OUTER", SYM(OUTER),0,0},
{ "OUTFILE", SYM(OUTFILE),0,0}, { "OUTFILE", SYM(OUTFILE),0,0},
{ "PACK_KEYS", SYM(PACK_KEYS_SYM),0,0}, { "PACK_KEYS", SYM(PACK_KEYS_SYM),0,0},
...@@ -337,6 +341,8 @@ static SYMBOL symbols[] = { ...@@ -337,6 +341,8 @@ static SYMBOL symbols[] = {
{ "SOME", SYM(ANY_SYM),0,0}, { "SOME", SYM(ANY_SYM),0,0},
{ "SONAME", SYM(UDF_SONAME_SYM),0,0}, { "SONAME", SYM(UDF_SONAME_SYM),0,0},
{ "SPATIAL", SYM(SPATIAL_SYM),0,0}, { "SPATIAL", SYM(SPATIAL_SYM),0,0},
{ "SPECIFIC", SYM(SPECIFIC_SYM),0,0},
{ "SPSET", SYM(SPSET_SYM),0,0},
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0}, { "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0}, { "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
{ "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0}, { "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
......
This diff is collapsed.
/* -*- C++ -*- */
/* Copyright (C) 2002 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _SP_HEAD_H_
#define _SP_HEAD_H_
#ifdef __GNUC__
#pragma interface /* gcc class implementation */
#endif
#include <stddef.h>
class sp_instr;
class sp_head : public Sql_alloc
{
sp_head(const sp_head &); /* Prevent use of these */
void operator=(sp_head &);
public:
static void *operator new(size_t size)
{
return (void*) sql_alloc((uint) size);
}
static void operator delete(void *ptr, size_t size)
{
/* Empty */
}
sp_head(LEX_STRING *name, LEX* lex);
int
create(THD *thd);
int
execute(THD *thd);
inline void
add_instr(sp_instr *i)
{
insert_dynamic(&m_instr, (gptr)&i);
}
inline uint
instructions()
{
return m_instr.elements;
}
// Resets lex in 'thd' and keeps a copy of the old one.
void
reset_lex(THD *thd);
// Restores lex in 'thd' from our copy, but keeps some status from the
// one in 'thd', like ptr, tables, fields, etc.
void
restore_lex(THD *thd);
private:
Item_string *m_name;
Item_string *m_defstr;
LEX *m_mylex; // My own lex
LEX m_lex; // Temp. store for the other lex
DYNAMIC_ARRAY m_instr; // The "instructions"
inline sp_instr *
get_instr(uint i)
{
sp_instr *in= NULL;
get_dynamic(&m_instr, (gptr)&in, i);
return in;
}
}; // class sp_head : public Sql_alloc
//
// Find a stored procedure given its name. Returns NULL if not
// found.
//
sp_head *
sp_find(THD *thd, Item_string *name);
int
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen);
int
sp_drop(THD *thd, char *name, uint namelen);
class sp_instr : public Sql_alloc
{
sp_instr(const sp_instr &); /* Prevent use of these */
void operator=(sp_instr &);
public:
// Should give each a name or type code for debugging purposes?
sp_instr()
: Sql_alloc()
{}
virtual ~sp_instr()
{}
// Execute this instrution. '*offsetp' will be set to an offset to the
// next instruction to execute. (For most instruction this will be 1,
// i.e. the following instruction.)
// Returns 0 on success, non-zero if some error occured.
virtual int
execute(THD *thd, int *offsetp)
{ // Default is a no-op.
*offsetp = 1; // Next instruction
return 0;
}
}; // class sp_instr : public Sql_alloc
//
// Call out to some prepared SQL statement.
//
class sp_instr_stmt : public sp_instr
{
sp_instr_stmt(const sp_instr_stmt &); /* Prevent use of these */
void operator=(sp_instr_stmt &);
public:
sp_instr_stmt()
: sp_instr()
{}
virtual ~sp_instr_stmt()
{}
virtual int execute(THD *thd, int *offsetp);
inline void
set_lex(LEX *lex)
{
memcpy(&m_lex, lex, sizeof(LEX));
}
inline LEX *
get_lex()
{
return &m_lex;
}
private:
LEX m_lex; // My own lex
}; // class sp_instr_stmt : public sp_instr
class sp_instr_set : public sp_instr
{
sp_instr_set(const sp_instr_set &); /* Prevent use of these */
void operator=(sp_instr_set &);
public:
sp_instr_set(uint offset, Item *val, enum enum_field_types type)
: sp_instr(), m_offset(offset), m_value(val), m_type(type)
{}
virtual ~sp_instr_set()
{}
virtual int execute(THD *thd, int *offsetp);
private:
uint m_offset;
Item *m_value;
enum enum_field_types m_type; // The declared type
}; // class sp_instr_set : public sp_instr
#endif /* _SP_HEAD_H_ */
/* Copyright (C) 2002 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef __GNUC__
#pragma implementation
#endif
#if defined(WIN32) || defined(__WIN__)
#undef SAFEMALLOC /* Problems with threads */
#endif
#include "mysql_priv.h"
#include "sp_pcontext.h"
sp_pcontext::sp_pcontext()
: m_params(0), m_framesize(0), m_i(0)
{
m_pvar_size = 16;
m_pvar = (sp_pvar_t *)my_malloc(m_pvar_size * sizeof(sp_pvar_t), MYF(MY_WME));
if (m_pvar)
memset(m_pvar, 0, m_pvar_size * sizeof(sp_pvar_t));
}
void
sp_pcontext::grow()
{
uint sz = m_pvar_size + 8;
sp_pvar_t *a = (sp_pvar_t *)my_realloc((char *)m_pvar,
sz * sizeof(sp_pvar_t),
MYF(MY_WME | MY_ALLOW_ZERO_PTR));
if (a)
{
m_pvar_size = sz;
m_pvar = a;
}
}
/* This does a linear search (from newer to older variables, in case
** we have shadowed names).
** It's possible to have a more efficient allocation and search method,
** but it might not be worth it. The typical number of parameters and
** variables will in most cases be low (a handfull).
** And this is only called during parsing.
*/
sp_pvar_t *
sp_pcontext::find_pvar(LEX_STRING *name)
{
String n(name->str, name->length, default_charset_info);
uint i = m_i;
while (i-- > 0)
{
if (stringcmp(&n, m_pvar[i].name->const_string()) == 0)
return m_pvar + i;
}
return NULL;
}
void
sp_pcontext::push(LEX_STRING *name, enum enum_field_types type,
sp_param_mode_t mode)
{
if (m_i >= m_pvar_size)
grow();
if (m_i < m_pvar_size)
{
if (m_i == m_framesize)
m_framesize += 1;
m_pvar[m_i].name= new Item_string(name->str, name->length,
default_charset_info);
m_pvar[m_i].type= type;
m_pvar[m_i].mode= mode;
m_pvar[m_i].offset= m_i;
m_pvar[m_i].isset= (mode == sp_param_out ? FALSE : TRUE);
m_i += 1;
}
}
/* -*- C++ -*- */
/* Copyright (C) 2002 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _SP_PCONTEXT_H_
#define _SP_PCONTEXT_H_
#ifdef __GNUC__
#pragma interface /* gcc class implementation */
#endif
typedef enum
{
sp_param_in,
sp_param_out,
sp_param_inout
} sp_param_mode_t;
typedef struct
{
Item_string *name;
enum enum_field_types type;
sp_param_mode_t mode;
uint offset; // Offset in current frame
my_bool isset;
} sp_pvar_t;
class sp_pcontext : public Sql_alloc
{
sp_pcontext(const sp_pcontext &); /* Prevent use of these */
void operator=(sp_pcontext &);
public:
sp_pcontext();
inline uint
max_framesize()
{
return m_framesize;
}
inline uint
current_framesize()
{
return m_i;
}
inline uint
params()
{
return m_params;
}
// Set the number of parameters to the current esize
inline void
set_params()
{
m_params= m_i;
}
inline void
set_type(uint i, enum enum_field_types type)
{
if (i < m_i)
m_pvar[i].type= type;
}
inline void
set_isset(uint i, my_bool val)
{
if (i < m_i)
m_pvar[i].isset= val;
}
void
push(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode);
inline void
pop(uint num = 1)
{
if (num >= m_i)
m_i -= num;
}
// Find by name
sp_pvar_t *
find_pvar(LEX_STRING *name);
// Find by index
sp_pvar_t *
find_pvar(uint i)
{
if (i >= m_i)
return NULL;
return m_pvar+i;
}
private:
uint m_params; // The number of parameters
uint m_framesize; // The maximum framesize
uint m_i; // The current index (during parsing)
sp_pvar_t *m_pvar;
uint m_pvar_size; // Current size of m_pvar.
void
grow();
}; // class sp_pcontext : public Sql_alloc
#endif /* _SP_PCONTEXT_H_ */
/* -*- C++ -*- */
/* Copyright (C) 2002 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef _SP_RCONTEXT_H_
#define _SP_RCONTEXT_H_
class sp_rcontext : public Sql_alloc
{
sp_rcontext(const sp_rcontext &); /* Prevent use of these */
void operator=(sp_rcontext &);
public:
sp_rcontext(uint size)
: m_count(0), m_size(size)
{
m_frame = (Item **)sql_alloc(size * sizeof(Item*));
m_outs = (int *)sql_alloc(size * sizeof(int));
}
~sp_rcontext()
{
// Not needed?
//sql_element_free(m_frame);
}
inline void
push_item(Item *i)
{
if (m_count < m_size)
m_frame[m_count++] = i;
}
inline void
set_item(uint idx, Item *i)
{
if (idx < m_count)
m_frame[idx] = i;
}
inline Item *
get_item(uint idx)
{
return m_frame[idx];
}
inline void
set_oindex(uint idx, int oidx)
{
m_outs[idx] = oidx;
}
inline int
get_oindex(uint idx)
{
return m_outs[idx];
}
private:
uint m_count;
uint m_size;
Item **m_frame;
int *m_outs;
}; // class sp_rcontext : public Sql_alloc
#endif /* _SP_RCONTEXT_H_ */
...@@ -81,7 +81,7 @@ extern "C" void free_user_var(user_var_entry *entry) ...@@ -81,7 +81,7 @@ extern "C" void free_user_var(user_var_entry *entry)
THD::THD():user_time(0), fatal_error(0), THD::THD():user_time(0), fatal_error(0),
last_insert_id_used(0), last_insert_id_used(0),
insert_id_used(0), rand_used(0), in_lock_tables(0), insert_id_used(0), rand_used(0), in_lock_tables(0),
global_read_lock(0), bootstrap(0) global_read_lock(0), bootstrap(0), spcont(NULL)
{ {
host=user=priv_user=db=query=ip=0; host=user=priv_user=db=query=ip=0;
host_or_ip="unknown ip"; host_or_ip="unknown ip";
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
class Query_log_event; class Query_log_event;
class Load_log_event; class Load_log_event;
class Slave_log_event; class Slave_log_event;
class sp_rcontext;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY }; enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY };
...@@ -515,6 +516,7 @@ class THD :public ilink { ...@@ -515,6 +516,7 @@ class THD :public ilink {
bool query_error, bootstrap, cleanup_done; bool query_error, bootstrap, cleanup_done;
bool volatile killed; bool volatile killed;
bool prepare_command; bool prepare_command;
sp_rcontext *spcont; // SP runtime context
/* /*
If we do a purge of binary logs, log index info of the threads If we do a purge of binary logs, log index info of the threads
......
...@@ -155,6 +155,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) ...@@ -155,6 +155,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
{ {
LEX *lex= &thd->lex; LEX *lex= &thd->lex;
lex->next_state=STATE_START; lex->next_state=STATE_START;
lex->buf= buf;
lex->end_of_query=(lex->ptr=buf)+length; lex->end_of_query=(lex->ptr=buf)+length;
lex->yylineno = 1; lex->yylineno = 1;
lex->select_lex.create_refs=lex->in_comment=0; lex->select_lex.create_refs=lex->in_comment=0;
...@@ -170,6 +171,8 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) ...@@ -170,6 +171,8 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
lex->slave_thd_opt=0; lex->slave_thd_opt=0;
lex->sql_command=SQLCOM_END; lex->sql_command=SQLCOM_END;
lex->safe_to_cache_query= 1; lex->safe_to_cache_query= 1;
lex->sphead= NULL;
lex->spcont= NULL;
bzero(&lex->mi,sizeof(lex->mi)); bzero(&lex->mi,sizeof(lex->mi));
return lex; return lex;
} }
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
class Table_ident; class Table_ident;
class sql_exchange; class sql_exchange;
class LEX_COLUMN; class LEX_COLUMN;
class sp_head;
class sp_instr;
class sp_pcontext;
/* /*
The following hack is needed because mysql_yacc.cc does not define The following hack is needed because mysql_yacc.cc does not define
...@@ -72,6 +75,8 @@ enum enum_sql_command { ...@@ -72,6 +75,8 @@ enum enum_sql_command {
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES, SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES,
SQLCOM_HELP, SQLCOM_HELP,
SQLCOM_CREATE_PROCEDURE, SQLCOM_CALL, SQLCOM_DROP_PROCEDURE,
SQLCOM_ALTER_PROCEDURE,
/* This should be the last !!! */ /* This should be the last !!! */
SQLCOM_END SQLCOM_END
...@@ -402,6 +407,7 @@ typedef struct st_lex ...@@ -402,6 +407,7 @@ typedef struct st_lex
SELECT_LEX_NODE *current_select; SELECT_LEX_NODE *current_select;
/* list of all SELECT_LEX */ /* list of all SELECT_LEX */
SELECT_LEX *all_selects_list; SELECT_LEX *all_selects_list;
uchar *buf; /* The beginning of string, used by SPs */
uchar *ptr,*tok_start,*tok_end,*end_of_query; uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name; char *length,*dec,*change,*name;
char *backup_dir; /* For RESTORE/BACKUP */ char *backup_dir; /* For RESTORE/BACKUP */
...@@ -459,6 +465,8 @@ typedef struct st_lex ...@@ -459,6 +465,8 @@ typedef struct st_lex
uint slave_thd_opt; uint slave_thd_opt;
CHARSET_INFO *charset; CHARSET_INFO *charset;
char *help_arg; char *help_arg;
sp_head *sphead;
sp_pcontext *spcont;
} LEX; } LEX;
......
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "ha_innodb.h" #include "ha_innodb.h"
#endif #endif
#include "sp_head.h"
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
/* /*
Without SSL the handshake consists of one packet. This packet Without SSL the handshake consists of one packet. This packet
...@@ -2739,6 +2741,84 @@ mysql_execute_command(THD *thd) ...@@ -2739,6 +2741,84 @@ mysql_execute_command(THD *thd)
res= -1; res= -1;
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
break; break;
case SQLCOM_CREATE_PROCEDURE:
if (!lex->sphead)
res= -1;
else
{
res= lex->sphead->create(thd);
if (res < 0)
{
// QQ Error!
}
send_ok(thd);
}
break;
case SQLCOM_CALL:
{
Item_string *s;
sp_head *sp;
s= (Item_string*)lex->value_list.head();
sp= sp_find(thd, s);
if (! sp)
{
// QQ Error!
res= -1;
}
else
{
res= sp->execute(thd);
if (res == 0)
send_ok(thd);
}
}
break;
case SQLCOM_ALTER_PROCEDURE:
{
Item_string *s;
sp_head *sp;
s= (Item_string*)lex->value_list.head();
sp= sp_find(thd, s);
if (! sp)
{
// QQ Error!
res= -1;
}
else
{
/* QQ This is an no-op right now, since we haven't
put the characteristics in yet. */
send_ok(thd);
}
}
break;
case SQLCOM_DROP_PROCEDURE:
{
Item_string *s;
sp_head *sp;
s = (Item_string*)lex->value_list.head();
sp = sp_find(thd, s);
if (! sp)
{
// QQ Error!
res= -1;
}
else
{
String *name = s->const_string();
res= sp_drop(thd, name->c_ptr(), name->length());
if (res < 0)
{
// QQ Error!
}
send_ok(thd);
}
}
break;
default: /* Impossible */ default: /* Impossible */
send_ok(thd); send_ok(thd);
break; break;
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
#include "sql_acl.h" #include "sql_acl.h"
#include "lex_symbol.h" #include "lex_symbol.h"
#include "item_create.h" #include "item_create.h"
#include "sp_head.h"
#include "sp_pcontext.h"
#include <myisam.h> #include <myisam.h>
#include <myisammrg.h> #include <myisammrg.h>
...@@ -120,6 +122,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -120,6 +122,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token AVG_SYM %token AVG_SYM
%token BEGIN_SYM %token BEGIN_SYM
%token BINLOG_SYM %token BINLOG_SYM
%token CALL_SYM
%token CHANGE %token CHANGE
%token CLIENT_SYM %token CLIENT_SYM
%token COMMENT_SYM %token COMMENT_SYM
...@@ -198,6 +201,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -198,6 +201,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token CONVERT_SYM %token CONVERT_SYM
%token DATABASES %token DATABASES
%token DATA_SYM %token DATA_SYM
%token DECLARE_SYM
%token DEFAULT %token DEFAULT
%token DELAYED_SYM %token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM %token DELAY_KEY_WRITE_SYM
...@@ -242,6 +246,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -242,6 +246,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token INFILE %token INFILE
%token INNER_SYM %token INNER_SYM
%token INNOBASE_SYM %token INNOBASE_SYM
%token INOUT_SYM
%token INTO %token INTO
%token IN_SYM %token IN_SYM
%token ISOLATION %token ISOLATION
...@@ -256,6 +261,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -256,6 +261,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token LIKE %token LIKE
%token LINES %token LINES
%token LOCAL_SYM %token LOCAL_SYM
%token LOCATOR_SYM
%token LOG_SYM %token LOG_SYM
%token LOGS_SYM %token LOGS_SYM
%token LONG_NUM %token LONG_NUM
...@@ -296,6 +302,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -296,6 +302,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token OR %token OR
%token OR_OR_CONCAT %token OR_OR_CONCAT
%token ORDER_SYM %token ORDER_SYM
%token OUT_SYM
%token OUTER %token OUTER
%token OUTFILE %token OUTFILE
%token DUMPFILE %token DUMPFILE
...@@ -334,6 +341,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -334,6 +341,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SIMPLE_SYM %token SIMPLE_SYM
%token SHUTDOWN %token SHUTDOWN
%token SPATIAL_SYM %token SPATIAL_SYM
%token SPECIFIC_SYM
%token SSL_SYM %token SSL_SYM
%token STARTING %token STARTING
%token STATUS_SYM %token STATUS_SYM
...@@ -518,6 +526,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -518,6 +526,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SQL_SMALL_RESULT %token SQL_SMALL_RESULT
%token SQL_BUFFER_RESULT %token SQL_BUFFER_RESULT
/* QQ This is a dummy, until we have solved the SET syntax problem. */
%token SPSET_SYM
%token ISSUER_SYM %token ISSUER_SYM
%token SUBJECT_SYM %token SUBJECT_SYM
%token CIPHER_SYM %token CIPHER_SYM
...@@ -666,8 +677,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -666,8 +677,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
union_clause union_list union_option union_clause union_list union_option
precision subselect_start opt_and precision subselect_start opt_and
subselect_end select_var_list select_var_list_init help opt_len subselect_end select_var_list select_var_list_init help opt_len
statement
END_OF_INPUT END_OF_INPUT
%type <NONE> call sp_proc_body sp_proc_stmts sp_proc_stmt
%type <num> sp_decls sp_decl sp_decl_idents sp_opt_inout
%type <NONE> %type <NONE>
'-' '+' '*' '/' '%' '(' ')' '-' '+' '*' '/' '%' '(' ')'
',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM ',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM
...@@ -693,10 +708,16 @@ query: ...@@ -693,10 +708,16 @@ query:
| verb_clause END_OF_INPUT {}; | verb_clause END_OF_INPUT {};
verb_clause: verb_clause:
statement
| begin
;
/* Verb clauses, except begin */
statement:
alter alter
| analyze | analyze
| backup | backup
| begin | call
| change | change
| check | check
| commit | commit
...@@ -874,7 +895,177 @@ create: ...@@ -874,7 +895,177 @@ create:
lex->udf.returns=(Item_result) $7; lex->udf.returns=(Item_result) $7;
lex->udf.dl=$9.str; lex->udf.dl=$9.str;
} }
; | CREATE PROCEDURE ident
{
LEX *lex= Lex;
lex->spcont = new sp_pcontext();
lex->sphead = new sp_head(&$3, lex);
}
'(' sp_dparam_list ')'
{
Lex->spcont->set_params();
}
sp_proc_body
{
Lex->sql_command= SQLCOM_CREATE_PROCEDURE;
}
;
call:
CALL_SYM ident
{
LEX *lex = Lex;
lex->sql_command= SQLCOM_CALL;
lex->value_list.empty();
lex->value_list.push_back(
(Item*)new Item_string($2.str, $2.length, default_charset_info));
}
'(' sp_cparam_list ')' {}
;
/* CALL parameters */
sp_cparam_list:
/* Empty */
| sp_cparams
;
sp_cparams:
sp_cparams ',' expr
{
Lex->value_list.push_back($3);
}
| expr
{
Lex->value_list.push_back($1);
}
;
/* SP parameter declaration list */
sp_dparam_list:
/* Empty */
| sp_dparams
;
sp_dparams:
sp_dparams ',' sp_dparam
| sp_dparam
;
sp_dparam:
sp_opt_inout ident type sp_opt_locator
{
Lex->spcont->push(&$2,
(enum enum_field_types)$3,
(sp_param_mode_t)$1);
}
;
sp_opt_inout:
/* Empty */ { $$= sp_param_in; }
| IN_SYM { $$= sp_param_in; }
| OUT_SYM { $$= sp_param_out; }
| INOUT_SYM { $$= sp_param_inout; }
;
sp_opt_locator:
/* Empty */
| AS LOCATOR_SYM
;
sp_proc_body:
{
Lex->sphead->reset_lex(YYTHD);
}
sp_proc_stmt
{
Lex->sphead->restore_lex(YYTHD);
}
| begin
sp_decls
sp_proc_stmts
END
{
Lex->spcont->pop($2);
}
;
sp_proc_stmts:
sp_proc_body ';'
| sp_proc_stmts sp_proc_body ';'
;
sp_decls:
/* Empty */
{
$$= 0;
}
| sp_decls sp_decl ';'
{
$$= $1 + $2;
}
;
sp_decl:
DECLARE_SYM sp_decl_idents type
{
LEX *lex= Lex;
uint max= lex->spcont->current_framesize();
for (uint i = max-$2 ; i < max ; i++)
{
lex->spcont->set_type(i, (enum enum_field_types)$3);
lex->spcont->set_isset(i, FALSE);
}
$$= $2;
}
;
sp_decl_idents:
ident
{
Lex->spcont->push(&$1, (enum_field_types)0, sp_param_in);
$$= 1;
}
| sp_decl_idents ',' ident
{
Lex->spcont->push(&$3, (enum_field_types)0, sp_param_in);
$$= $1 + 1;
}
;
/* Dummy for the spset thing. Will go away when the SET problem is fixed. */
sp_proc_stmt:
statement
{
LEX *lex= Lex;
sp_instr_stmt *i= new sp_instr_stmt();
i->set_lex(lex);
lex->sphead->add_instr(i);
}
|
/* QQ Dummy. We need to fix the old SET syntax to make it work for
local SP variables as well. */
SPSET_SYM ident EQ expr
{
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
sp_pvar_t *spv;
if (!spc || !(spv = spc->find_pvar(&$2)))
YYABORT; /* Unknow variable */
else
{
/* QQ Check type match! */
sp_instr_set *i = new sp_instr_set(spv->offset, $4, spv->type);
lex->sphead->add_instr(i);
spv->isset= TRUE;
}
}
;
create2: create2:
'(' field_list ')' opt_create_table_options create3 {} '(' field_list ')' opt_create_table_options create3 {}
...@@ -1393,8 +1584,27 @@ alter: ...@@ -1393,8 +1584,27 @@ alter:
lex->sql_command=SQLCOM_ALTER_DB; lex->sql_command=SQLCOM_ALTER_DB;
lex->name=$3.str; lex->name=$3.str;
lex->create_info.table_charset=$4; lex->create_info.table_charset=$4;
}; }
| ALTER PROCEDURE opt_specific ident
/* QQ Characteristics missing for now */
opt_restrict
{
LEX *lex=Lex;
/* This is essensially an no-op right now, since we haven't
put the characteristics in yet. */
lex->sql_command= SQLCOM_ALTER_PROCEDURE;
lex->value_list.empty();
lex->value_list.push_back(
(Item*)new Item_string($4.str, $4.length, default_charset_info));
}
;
opt_specific:
/* Empty */
|
SPECIFIC_SYM
;
alter_list: alter_list:
| alter_list_item | alter_list_item
...@@ -2905,7 +3115,16 @@ drop: ...@@ -2905,7 +3115,16 @@ drop:
LEX *lex=Lex; LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_FUNCTION; lex->sql_command = SQLCOM_DROP_FUNCTION;
lex->udf.name=$3.str; lex->udf.name=$3.str;
}; }
| DROP PROCEDURE ident opt_restrict
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_PROCEDURE;
lex->value_list.empty();
lex->value_list.push_back(
(Item*)new Item_string($3.str, $3.length, default_charset_info));
}
;
table_list: table_list:
...@@ -2958,7 +3177,6 @@ replace: ...@@ -2958,7 +3177,6 @@ replace:
} }
insert_field_spec insert_field_spec
{} {}
{}
; ;
insert_lock_option: insert_lock_option:
...@@ -3642,8 +3860,25 @@ order_ident: ...@@ -3642,8 +3860,25 @@ order_ident:
simple_ident: simple_ident:
ident ident
{ {
SELECT_LEX_NODE *sel=Select; sp_pvar_t *spv;
$$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str); LEX *lex = Lex;
sp_pcontext *spc = lex->spcont;
if (spc && (spv = spc->find_pvar(&$1)))
{ /* We're compiling a stored procedure and found a variable */
if (lex->sql_command != SQLCOM_CALL && ! spv->isset)
{
printf("QQ Referring to an unitialized variable\n");
YYABORT; /* QQ Referring to an unitialized variable */
}
else
$$ = (Item*) new Item_splocal(spv->offset);
}
else
{
SELECT_LEX_NODE *sel=Select;
$$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str);
}
} }
| ident '.' ident | ident '.' ident
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment