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

Fixed bugs in the parameter evaluation and modified the execution engine

for better jump support. Some flow control support added too (but not
complete).
parent aae07a4d
...@@ -59,6 +59,7 @@ static SYMBOL symbols[] = { ...@@ -59,6 +59,7 @@ static SYMBOL symbols[] = {
{ "ANY", SYM(ANY_SYM),0,0}, { "ANY", SYM(ANY_SYM),0,0},
{ "AS", SYM(AS),0,0}, { "AS", SYM(AS),0,0},
{ "ASC", SYM(ASC),0,0}, { "ASC", SYM(ASC),0,0},
{ "ASENSITIVE", SYM(ASENSITIVE_SYM),0,0},
{ "AVG", SYM(AVG_SYM),0,0}, { "AVG", SYM(AVG_SYM),0,0},
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0}, { "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0},
{ "AUTO_INCREMENT", SYM(AUTO_INC),0,0}, { "AUTO_INCREMENT", SYM(AUTO_INC),0,0},
...@@ -107,6 +108,7 @@ static SYMBOL symbols[] = { ...@@ -107,6 +108,7 @@ static SYMBOL symbols[] = {
{ "CURRENT_DATE", SYM(CURDATE),0,0}, { "CURRENT_DATE", SYM(CURDATE),0,0},
{ "CURRENT_TIME", SYM(CURTIME),0,0}, { "CURRENT_TIME", SYM(CURTIME),0,0},
{ "CURRENT_TIMESTAMP", SYM(NOW_SYM),0,0}, { "CURRENT_TIMESTAMP", SYM(NOW_SYM),0,0},
{ "CURSOR", SYM(CURSOR_SYM),0,0},
{ "DATA", SYM(DATA_SYM),0,0}, { "DATA", SYM(DATA_SYM),0,0},
{ "DATABASE", SYM(DATABASE),0,0}, { "DATABASE", SYM(DATABASE),0,0},
{ "DATABASES", SYM(DATABASES),0,0}, { "DATABASES", SYM(DATABASES),0,0},
...@@ -141,6 +143,7 @@ static SYMBOL symbols[] = { ...@@ -141,6 +143,7 @@ static SYMBOL symbols[] = {
{ "ERRORS", SYM(ERRORS),0,0}, { "ERRORS", SYM(ERRORS),0,0},
{ "END", SYM(END),0,0}, { "END", SYM(END),0,0},
{ "ELSE", SYM(ELSE),0,0}, { "ELSE", SYM(ELSE),0,0},
{ "ELSEIF", SYM(ELSEIF_SYM),0,0},
{ "ESCAPE", SYM(ESCAPE_SYM),0,0}, { "ESCAPE", SYM(ESCAPE_SYM),0,0},
{ "ESCAPED", SYM(ESCAPED),0,0}, { "ESCAPED", SYM(ESCAPED),0,0},
{ "ENABLE", SYM(ENABLE_SYM),0,0}, { "ENABLE", SYM(ENABLE_SYM),0,0},
...@@ -196,6 +199,7 @@ static SYMBOL symbols[] = { ...@@ -196,6 +199,7 @@ static SYMBOL symbols[] = {
{ "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}, { "INOUT", SYM(INOUT_SYM),0,0},
{ "INSENSITIVE", SYM(INSENSITIVE_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},
...@@ -213,12 +217,14 @@ static SYMBOL symbols[] = { ...@@ -213,12 +217,14 @@ static SYMBOL symbols[] = {
{ "ISOLATION", SYM(ISOLATION),0,0}, { "ISOLATION", SYM(ISOLATION),0,0},
{ "ISAM", SYM(ISAM_SYM),0,0}, { "ISAM", SYM(ISAM_SYM),0,0},
{ "ISSUER", SYM(ISSUER_SYM),0,0}, { "ISSUER", SYM(ISSUER_SYM),0,0},
{ "ITERATE", SYM(ITERATE_SYM),0,0},
{ "JOIN", SYM(JOIN_SYM),0,0}, { "JOIN", SYM(JOIN_SYM),0,0},
{ "KEY", SYM(KEY_SYM),0,0}, { "KEY", SYM(KEY_SYM),0,0},
{ "KEYS", SYM(KEYS),0,0}, { "KEYS", SYM(KEYS),0,0},
{ "KILL", SYM(KILL_SYM),0,0}, { "KILL", SYM(KILL_SYM),0,0},
{ "LAST", SYM(LAST_SYM),0,0}, { "LAST", SYM(LAST_SYM),0,0},
{ "LEADING", SYM(LEADING),0,0}, { "LEADING", SYM(LEADING),0,0},
{ "LEAVE", SYM(LEAVE_SYM),0,0},
{ "LEFT", SYM(LEFT),0,0}, { "LEFT", SYM(LEFT),0,0},
{ "LEVEL", SYM(LEVEL_SYM),0,0}, { "LEVEL", SYM(LEVEL_SYM),0,0},
{ "LIKE", SYM(LIKE),0,0}, { "LIKE", SYM(LIKE),0,0},
...@@ -233,6 +239,7 @@ static SYMBOL symbols[] = { ...@@ -233,6 +239,7 @@ static SYMBOL symbols[] = {
{ "LOGS", SYM(LOGS_SYM),0,0}, { "LOGS", SYM(LOGS_SYM),0,0},
{ "LONG", SYM(LONG_SYM),0,0}, { "LONG", SYM(LONG_SYM),0,0},
{ "LONGBLOB", SYM(LONGBLOB),0,0}, { "LONGBLOB", SYM(LONGBLOB),0,0},
{ "LOOP", SYM(LOOP_SYM),0,0},
{ "LONGTEXT", SYM(LONGTEXT),0,0}, { "LONGTEXT", SYM(LONGTEXT),0,0},
{ "LOW_PRIORITY", SYM(LOW_PRIORITY),0,0}, { "LOW_PRIORITY", SYM(LOW_PRIORITY),0,0},
{ "MASTER", SYM(MASTER_SYM),0,0}, { "MASTER", SYM(MASTER_SYM),0,0},
...@@ -313,6 +320,7 @@ static SYMBOL symbols[] = { ...@@ -313,6 +320,7 @@ static SYMBOL symbols[] = {
{ "REPEATABLE", SYM(REPEATABLE_SYM),0,0}, { "REPEATABLE", SYM(REPEATABLE_SYM),0,0},
{ "REQUIRE", SYM(REQUIRE_SYM),0,0}, { "REQUIRE", SYM(REQUIRE_SYM),0,0},
{ "RESET", SYM(RESET_SYM),0,0}, { "RESET", SYM(RESET_SYM),0,0},
{ "UNTIL", SYM(UNTIL_SYM),0,0},
{ "USER_RESOURCES", SYM(RESOURCES),0,0}, { "USER_RESOURCES", SYM(RESOURCES),0,0},
{ "RESTORE", SYM(RESTORE_SYM),0,0}, { "RESTORE", SYM(RESTORE_SYM),0,0},
{ "RESTRICT", SYM(RESTRICT),0,0}, { "RESTRICT", SYM(RESTRICT),0,0},
...@@ -327,6 +335,7 @@ static SYMBOL symbols[] = { ...@@ -327,6 +335,7 @@ static SYMBOL symbols[] = {
{ "RTREE", SYM(RTREE_SYM),0,0}, { "RTREE", SYM(RTREE_SYM),0,0},
{ "SECOND", SYM(SECOND_SYM),0,0}, { "SECOND", SYM(SECOND_SYM),0,0},
{ "SELECT", SYM(SELECT_SYM),0,0}, { "SELECT", SYM(SELECT_SYM),0,0},
{ "SENSITIVE", SYM(SENSITIVE_SYM),0,0},
{ "SERIAL", SYM(SERIAL_SYM),0,0}, { "SERIAL", SYM(SERIAL_SYM),0,0},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0}, { "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
{ "SESSION", SYM(SESSION_SYM),0,0}, { "SESSION", SYM(SESSION_SYM),0,0},
...@@ -401,6 +410,7 @@ static SYMBOL symbols[] = { ...@@ -401,6 +410,7 @@ static SYMBOL symbols[] = {
{ "WRITE", SYM(WRITE_SYM),0,0}, { "WRITE", SYM(WRITE_SYM),0,0},
{ "WHEN", SYM(WHEN_SYM),0,0}, { "WHEN", SYM(WHEN_SYM),0,0},
{ "WHERE", SYM(WHERE),0,0}, { "WHERE", SYM(WHERE),0,0},
{ "WHILE", SYM(WHILE_SYM),0,0},
{ "XOR", SYM(XOR),0,0}, { "XOR", SYM(XOR),0,0},
{ "X509", SYM(X509_SYM),0,0}, { "X509", SYM(X509_SYM),0,0},
{ "YEAR", SYM(YEAR_SYM),0,0}, { "YEAR", SYM(YEAR_SYM),0,0},
......
...@@ -59,9 +59,9 @@ eval_func_item(Item *it, enum enum_field_types type) ...@@ -59,9 +59,9 @@ eval_func_item(Item *it, enum enum_field_types type)
{ {
char buffer[MAX_FIELD_WIDTH]; char buffer[MAX_FIELD_WIDTH];
String tmp(buffer, sizeof(buffer), default_charset_info); String tmp(buffer, sizeof(buffer), default_charset_info);
String *s= it->val_str(&tmp);
(void)it->val_str(&tmp); it= new Item_string(s->c_ptr_quick(), s->length(), default_charset_info);
it= new Item_string(buffer, sizeof(buffer), default_charset_info);
break; break;
} }
case MYSQL_TYPE_NULL: case MYSQL_TYPE_NULL:
...@@ -149,16 +149,22 @@ sp_head::execute(THD *thd) ...@@ -149,16 +149,22 @@ sp_head::execute(THD *thd)
{ {
sp_pvar_t *pvar = pctx->find_pvar(i); sp_pvar_t *pvar = pctx->find_pvar(i);
// QQ Passing an argument is, in a sense, a "SET". We have to evaluate if (! pvar)
// any expression at this point. nctx->set_oindex(i, -1); // Shouldn't happen
nctx->push_item(it->this_item()); else
{
if (pvar->mode == sp_param_out)
nctx->push_item(it->this_item()); // OUT
else
nctx->push_item(eval_func_item(it, pvar->type)); // IN or INOUT
// Note: If it's OUT or INOUT, it must be a variable. // Note: If it's OUT or INOUT, it must be a variable.
// QQ: Need to handle "global" user/host variables too!!! // QQ: Need to handle "global" user/host variables too!!!
if (!pvar || pvar->mode == sp_param_in) if (pvar->mode == sp_param_in)
nctx->set_oindex(i, -1); nctx->set_oindex(i, -1); // IN
else else // OUT or INOUT
nctx->set_oindex(i, static_cast<Item_splocal *>(it)->get_offset()); nctx->set_oindex(i, static_cast<Item_splocal *>(it)->get_offset());
} }
}
// The rest of the frame are local variables which are all IN. // The rest of the frame are local variables which are all IN.
// QQ We haven't found any hint of what the value is when unassigned, // QQ We haven't found any hint of what the value is when unassigned,
// so we set it to NULL for now. It's an error to refer to an // so we set it to NULL for now. It's an error to refer to an
...@@ -176,14 +182,12 @@ sp_head::execute(THD *thd) ...@@ -176,14 +182,12 @@ sp_head::execute(THD *thd)
while (ret == 0) while (ret == 0)
{ {
int offset;
sp_instr *i; sp_instr *i;
i = get_instr(ip); // Returns NULL when we're done. i = get_instr(ip); // Returns NULL when we're done.
if (i == NULL) if (i == NULL)
break; break;
ret= i->execute(thd, &offset); ret= i->execute(thd, &ip);
ip += offset;
} }
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
...@@ -250,6 +254,27 @@ sp_head::restore_lex(THD *thd) ...@@ -250,6 +254,27 @@ sp_head::restore_lex(THD *thd)
memcpy(&thd->lex, &m_lex, sizeof(LEX)); // Restore lex memcpy(&thd->lex, &m_lex, sizeof(LEX)); // Restore lex
} }
void
sp_head::push_backpatch(uint ip)
{
(void)m_backpatch.push_front(&ip);
}
void
sp_head::backpatch(uint dest)
{
while (! m_backpatch.is_empty())
{
uint *ip= m_backpatch.pop();
sp_instr_jump *i= static_cast<sp_instr_jump *>(get_instr(*ip));
i->set_destination(dest);
}
}
// ------------------------------------------------------------------
// Finds the SP 'name'. Currently this always reads from the database // Finds the SP 'name'. Currently this always reads from the database
// and prepares (parse) it, but in the future it will first look in // and prepares (parse) it, but in the future it will first look in
// the in-memory cache for SPs. (And store newly prepared SPs there of // the in-memory cache for SPs. (And store newly prepared SPs there of
...@@ -350,12 +375,13 @@ sp_drop(THD *thd, char *name, uint namelen) ...@@ -350,12 +375,13 @@ sp_drop(THD *thd, char *name, uint namelen)
} }
// ------------------------------------------------------------------
// //
// sp_instr_stmt // sp_instr_stmt
// //
int int
sp_instr_stmt::execute(THD *thd, int *offsetp) sp_instr_stmt::execute(THD *thd, uint *nextp)
{ {
LEX olex; // The other lex LEX olex; // The other lex
...@@ -368,7 +394,7 @@ sp_instr_stmt::execute(THD *thd, int *offsetp) ...@@ -368,7 +394,7 @@ sp_instr_stmt::execute(THD *thd, int *offsetp)
memcpy(&thd->lex, &olex, sizeof(LEX)); // Restore the other lex memcpy(&thd->lex, &olex, sizeof(LEX)); // Restore the other lex
*offsetp = 1; *nextp = m_ip+1;
return 0; return 0;
} }
...@@ -376,9 +402,41 @@ sp_instr_stmt::execute(THD *thd, int *offsetp) ...@@ -376,9 +402,41 @@ sp_instr_stmt::execute(THD *thd, int *offsetp)
// sp_instr_set // sp_instr_set
// //
int int
sp_instr_set::execute(THD *thd, int *offsetp) sp_instr_set::execute(THD *thd, uint *nextp)
{ {
thd->spcont->set_item(m_offset, eval_func_item(m_value, m_type)); thd->spcont->set_item(m_offset, eval_func_item(m_value, m_type));
*offsetp = 1; *nextp = m_ip+1;
return 0;
}
//
// sp_instr_jump_if
//
int
sp_instr_jump_if::execute(THD *thd, uint *nextp)
{
Item *it= eval_func_item(m_expr, MYSQL_TYPE_TINY);
if (it->val_int())
*nextp = m_dest;
else
*nextp = m_ip+1;
return 0;
}
//
// sp_instr_jump_if_not
//
int
sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{
Item *it= eval_func_item(m_expr, MYSQL_TYPE_TINY);
if (! it->val_int())
*nextp = m_dest;
else
*nextp = m_ip+1;
return 0; return 0;
} }
...@@ -72,6 +72,12 @@ class sp_head : public Sql_alloc ...@@ -72,6 +72,12 @@ class sp_head : public Sql_alloc
void void
restore_lex(THD *thd); restore_lex(THD *thd);
void
push_backpatch(uint ip);
void
backpatch(uint dest);
private: private:
Item_string *m_name; Item_string *m_name;
...@@ -79,6 +85,7 @@ class sp_head : public Sql_alloc ...@@ -79,6 +85,7 @@ class sp_head : public Sql_alloc
LEX *m_mylex; // My own lex LEX *m_mylex; // My own lex
LEX m_lex; // Temp. store for the other lex LEX m_lex; // Temp. store for the other lex
DYNAMIC_ARRAY m_instr; // The "instructions" DYNAMIC_ARRAY m_instr; // The "instructions"
List<uint> m_backpatch; // Instructions needing backpaching
inline sp_instr * inline sp_instr *
get_instr(uint i) get_instr(uint i)
...@@ -106,6 +113,10 @@ int ...@@ -106,6 +113,10 @@ int
sp_drop(THD *thd, char *name, uint namelen); sp_drop(THD *thd, char *name, uint namelen);
//
// "Instructions"...
//
class sp_instr : public Sql_alloc class sp_instr : public Sql_alloc
{ {
sp_instr(const sp_instr &); /* Prevent use of these */ sp_instr(const sp_instr &); /* Prevent use of these */
...@@ -114,24 +125,28 @@ class sp_instr : public Sql_alloc ...@@ -114,24 +125,28 @@ class sp_instr : public Sql_alloc
public: public:
// Should give each a name or type code for debugging purposes? // Should give each a name or type code for debugging purposes?
sp_instr() sp_instr(uint ip)
: Sql_alloc() : Sql_alloc(), m_ip(ip)
{} {}
virtual ~sp_instr() virtual ~sp_instr()
{} {}
// Execute this instrution. '*offsetp' will be set to an offset to the // Execute this instrution. '*nextp' will be set to the index of the next
// next instruction to execute. (For most instruction this will be 1, // instruction to execute. (For most instruction this will be the
// i.e. the following instruction.) // instruction following this one.)
// Returns 0 on success, non-zero if some error occured. // Returns 0 on success, non-zero if some error occured.
virtual int virtual int
execute(THD *thd, int *offsetp) execute(THD *thd, uint *nextp)
{ // Default is a no-op. { // Default is a no-op.
*offsetp = 1; // Next instruction *nextp = m_ip+1; // Next instruction
return 0; return 0;
} }
protected:
uint m_ip; // My index
}; // class sp_instr : public Sql_alloc }; // class sp_instr : public Sql_alloc
...@@ -145,14 +160,14 @@ class sp_instr_stmt : public sp_instr ...@@ -145,14 +160,14 @@ class sp_instr_stmt : public sp_instr
public: public:
sp_instr_stmt() sp_instr_stmt(uint ip)
: sp_instr() : sp_instr(ip)
{} {}
virtual ~sp_instr_stmt() virtual ~sp_instr_stmt()
{} {}
virtual int execute(THD *thd, int *offsetp); virtual int execute(THD *thd, uint *nextp);
inline void inline void
set_lex(LEX *lex) set_lex(LEX *lex)
...@@ -180,21 +195,114 @@ class sp_instr_set : public sp_instr ...@@ -180,21 +195,114 @@ class sp_instr_set : public sp_instr
public: public:
sp_instr_set(uint offset, Item *val, enum enum_field_types type) sp_instr_set(uint ip, uint offset, Item *val, enum enum_field_types type)
: sp_instr(), m_offset(offset), m_value(val), m_type(type) : sp_instr(ip), m_offset(offset), m_value(val), m_type(type)
{} {}
virtual ~sp_instr_set() virtual ~sp_instr_set()
{} {}
virtual int execute(THD *thd, int *offsetp); virtual int execute(THD *thd, uint *nextp);
private: private:
uint m_offset; uint m_offset; // Frame offset
Item *m_value; Item *m_value;
enum enum_field_types m_type; // The declared type enum enum_field_types m_type; // The declared type
}; // class sp_instr_set : public sp_instr }; // class sp_instr_set : public sp_instr
class sp_instr_jump : public sp_instr
{
sp_instr_jump(const sp_instr_jump &); /* Prevent use of these */
void operator=(sp_instr_jump &);
public:
sp_instr_jump(uint ip)
: sp_instr(ip)
{}
sp_instr_jump(uint ip, uint dest)
: sp_instr(ip), m_dest(dest)
{}
virtual ~sp_instr_jump()
{}
virtual int execute(THD *thd, uint *nextp)
{
*nextp= m_dest;
return 0;
}
virtual void
set_destination(uint dest)
{
m_dest= dest;
}
private:
int m_dest; // Where we will go
}; // class sp_instr_jump : public sp_instr
class sp_instr_jump_if : public sp_instr_jump
{
sp_instr_jump_if(const sp_instr_jump_if &); /* Prevent use of these */
void operator=(sp_instr_jump_if &);
public:
sp_instr_jump_if(uint ip, Item *i)
: sp_instr_jump(ip), m_expr(i)
{}
sp_instr_jump_if(uint ip, Item *i, uint dest)
: sp_instr_jump(ip, dest), m_expr(i)
{}
virtual ~sp_instr_jump_if()
{}
virtual int execute(THD *thd, uint *nextp);
private:
int m_dest; // Where we will go
Item *m_expr; // The condition
}; // class sp_instr_jump_if : public sp_instr_jump
class sp_instr_jump_if_not : public sp_instr_jump
{
sp_instr_jump_if_not(const sp_instr_jump_if_not &); /* Prevent use of these */
void operator=(sp_instr_jump_if_not &);
public:
sp_instr_jump_if_not(uint ip, Item *i)
: sp_instr_jump(ip), m_expr(i)
{}
sp_instr_jump_if_not(uint ip, Item *i, uint dest)
: sp_instr_jump(ip, dest), m_expr(i)
{}
virtual ~sp_instr_jump_if_not()
{}
virtual int execute(THD *thd, uint *nextp);
private:
int m_dest; // Where we will go
Item *m_expr; // The condition
}; // class sp_instr_jump_if_not : public sp_instr_jump
#endif /* _SP_HEAD_H_ */ #endif /* _SP_HEAD_H_ */
...@@ -24,14 +24,16 @@ ...@@ -24,14 +24,16 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#include "sp_pcontext.h" #include "sp_pcontext.h"
#include "sp_head.h"
sp_pcontext::sp_pcontext() sp_pcontext::sp_pcontext()
: m_params(0), m_framesize(0), m_i(0) : m_params(0), m_framesize(0), m_i(0), m_genlab(0)
{ {
m_pvar_size = 16; m_pvar_size = 16;
m_pvar = (sp_pvar_t *)my_malloc(m_pvar_size * sizeof(sp_pvar_t), MYF(MY_WME)); m_pvar = (sp_pvar_t *)my_malloc(m_pvar_size * sizeof(sp_pvar_t), MYF(MY_WME));
if (m_pvar) if (m_pvar)
memset(m_pvar, 0, m_pvar_size * sizeof(sp_pvar_t)); memset(m_pvar, 0, m_pvar_size * sizeof(sp_pvar_t));
m_label.empty();
} }
void void
...@@ -89,3 +91,41 @@ sp_pcontext::push(LEX_STRING *name, enum enum_field_types type, ...@@ -89,3 +91,41 @@ sp_pcontext::push(LEX_STRING *name, enum enum_field_types type,
m_i += 1; m_i += 1;
} }
} }
void
sp_pcontext::push_label(char *name, uint ip)
{
sp_label_t *lab = (sp_label_t *)my_malloc(sizeof(sp_label_t), MYF(MY_WME));
if (lab)
{
lab->name= name;
lab->ip= ip;
m_label.push_front(lab);
}
}
void
sp_pcontext::push_gen_label(uint ip)
{
char *s= my_malloc(10, MYF(MY_WME)); // 10=...
if (s)
{
sprintf(s, ".%08x", m_genlab++); // ...9+1
push_label(s, ip);
}
}
sp_label_t *
sp_pcontext::find_label(char *name)
{
List_iterator_fast<sp_label_t> li(m_label);
sp_label_t *lab;
while ((lab= li++))
if (strcasecmp(name, lab->name) == 0)
return lab;
return NULL;
}
...@@ -38,6 +38,12 @@ typedef struct ...@@ -38,6 +38,12 @@ typedef struct
my_bool isset; my_bool isset;
} sp_pvar_t; } sp_pvar_t;
typedef struct
{
char *name;
uint ip; // Instruction index
} sp_label_t;
class sp_pcontext : public Sql_alloc class sp_pcontext : public Sql_alloc
{ {
sp_pcontext(const sp_pcontext &); /* Prevent use of these */ sp_pcontext(const sp_pcontext &); /* Prevent use of these */
...@@ -89,6 +95,7 @@ class sp_pcontext : public Sql_alloc ...@@ -89,6 +95,7 @@ class sp_pcontext : public Sql_alloc
void void
push(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode); push(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode);
// Pop the last 'num' slots of the frame
inline void inline void
pop(uint num = 1) pop(uint num = 1)
{ {
...@@ -109,6 +116,21 @@ class sp_pcontext : public Sql_alloc ...@@ -109,6 +116,21 @@ class sp_pcontext : public Sql_alloc
return m_pvar+i; return m_pvar+i;
} }
void
push_label(char *name, uint ip);
void
push_gen_label(uint ip);
sp_label_t *
find_label(char *name);
inline void
pop_label()
{
m_label.pop();
}
private: private:
uint m_params; // The number of parameters uint m_params; // The number of parameters
...@@ -121,6 +143,9 @@ class sp_pcontext : public Sql_alloc ...@@ -121,6 +143,9 @@ class sp_pcontext : public Sql_alloc
void void
grow(); grow();
List<sp_label_t> m_label; // The label list
uint m_genlab; // Gen. label counter
}; // class sp_pcontext : public Sql_alloc }; // class sp_pcontext : public Sql_alloc
......
...@@ -526,6 +526,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -526,6 +526,16 @@ 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
%token CURSOR_SYM
%token ELSEIF_SYM
%token ITERATE_SYM
%token LEAVE_SYM
%token LOOP_SYM
%token UNTIL_SYM
%token WHILE_SYM
%token ASENSITIVE_SYM
%token INSENSITIVE_SYM
%token SENSITIVE_SYM
/* QQ This is a dummy, until we have solved the SET syntax problem. */ /* QQ This is a dummy, until we have solved the SET syntax problem. */
%token SPSET_SYM %token SPSET_SYM
...@@ -680,7 +690,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -680,7 +690,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
statement statement
END_OF_INPUT END_OF_INPUT
%type <NONE> call sp_proc_body sp_proc_stmts sp_proc_stmt %type <NONE> call sp_proc_stmts sp_proc_stmt
%type <num> sp_decls sp_decl sp_decl_idents sp_opt_inout %type <num> sp_decls sp_decl sp_decl_idents sp_opt_inout
%type <NONE> %type <NONE>
...@@ -906,7 +916,7 @@ create: ...@@ -906,7 +916,7 @@ create:
{ {
Lex->spcont->set_params(); Lex->spcont->set_params();
} }
sp_proc_body sp_proc_stmt
{ {
Lex->sql_command= SQLCOM_CREATE_PROCEDURE; Lex->sql_command= SQLCOM_CREATE_PROCEDURE;
} }
...@@ -974,26 +984,9 @@ sp_opt_locator: ...@@ -974,26 +984,9 @@ sp_opt_locator:
| AS LOCATOR_SYM | 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_stmts:
sp_proc_body ';' sp_proc_stmt ';'
| sp_proc_stmts sp_proc_body ';' | sp_proc_stmts sp_proc_stmt ';'
; ;
sp_decls: sp_decls:
...@@ -1037,13 +1030,68 @@ sp_decl_idents: ...@@ -1037,13 +1030,68 @@ sp_decl_idents:
/* Dummy for the spset thing. Will go away when the SET problem is fixed. */ /* Dummy for the spset thing. Will go away when the SET problem is fixed. */
sp_proc_stmt: sp_proc_stmt:
{
Lex->sphead->reset_lex(YYTHD);
}
statement statement
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_instr_stmt *i= new sp_instr_stmt(); sp_instr_stmt *i= new sp_instr_stmt(lex->sphead->instructions());
i->set_lex(lex); i->set_lex(lex);
lex->sphead->add_instr(i); lex->sphead->add_instr(i);
lex->sphead->restore_lex(YYTHD);
}
/* | sp_if
| sp_case */
| sp_labeled_control
{}
| { /* Unlabeled controls get a secret label. */
LEX *lex= Lex;
Lex->spcont->push_gen_label(lex->sphead->instructions());
}
sp_unlabeled_control
{
/* QQ backpatch here */
Lex->spcont->pop_label();
}
| LEAVE_SYM IDENT
{
LEX *lex= Lex;
sp_label_t *lab= lex->spcont->find_label($2.str);
if (! lab)
{
printf("QQ LEAVE with no matching label\n");
YYABORT;
}
else
{
uint ip= lex->sphead->instructions();
sp_instr_jump *i= new sp_instr_jump(ip, 0);
lex->sphead->push_backpatch(ip);
lex->sphead->add_instr(i);
}
}
| ITERATE_SYM IDENT
{
LEX *lex= Lex;
sp_label_t *lab= lex->spcont->find_label($2.str);
if (! lab)
{
printf("QQ ITERATE with no matching label\n");
YYABORT;
}
else
{
uint ip= lex->sphead->instructions();
sp_instr_jump *i= new sp_instr_jump(ip, lab->ip);
lex->sphead->add_instr(i);
}
} }
| |
/* QQ Dummy. We need to fix the old SET syntax to make it work for /* QQ Dummy. We need to fix the old SET syntax to make it work for
...@@ -1059,7 +1107,8 @@ sp_proc_stmt: ...@@ -1059,7 +1107,8 @@ sp_proc_stmt:
else else
{ {
/* QQ Check type match! */ /* QQ Check type match! */
sp_instr_set *i = new sp_instr_set(spv->offset, $4, spv->type); sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
spv->offset, $4, spv->type);
lex->sphead->add_instr(i); lex->sphead->add_instr(i);
spv->isset= TRUE; spv->isset= TRUE;
...@@ -1067,6 +1116,63 @@ sp_proc_stmt: ...@@ -1067,6 +1116,63 @@ sp_proc_stmt:
} }
; ;
sp_labeled_control:
IDENT ':'
{
LEX *lex= Lex;
sp_label_t *lab= lex->spcont->find_label($1.str);
if (lab)
{
printf("QQ Redefining label\n");
YYABORT;
}
else
lex->spcont->push_label($1.str,
lex->sphead->instructions());
}
sp_unlabeled_control IDENT
{
LEX *lex= Lex;
sp_label_t *lab= lex->spcont->find_label($5.str);
if (! lab)
{
printf("QQ end-label without match\n");
YYABORT;
}
else if (strcasecmp($5.str, lab->name) != 0)
{
printf("QQ mismatching labels\n");
YYABORT;
}
else
{
/* QQ backpatch here */
lex->spcont->pop_label();
}
}
;
sp_unlabeled_control:
begin
sp_decls
sp_proc_stmts
END
{
Lex->spcont->pop($2);
}
| LOOP_SYM
sp_proc_stmts
END LOOP_SYM
| WHILE_SYM expr DO_SYM
sp_proc_stmts
END WHILE_SYM
| FUNC_ARG2 /* "REPEAT" actually... */
sp_proc_stmts
UNTIL_SYM expr END FUNC_ARG2
;
create2: create2:
'(' field_list ')' opt_create_table_options create3 {} '(' field_list ')' opt_create_table_options create3 {}
| opt_create_table_options create3 {} | opt_create_table_options create3 {}
......
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