Commit a2009dea authored by unknown's avatar unknown

Fixed bugs in the parameter evaluation and modified the execution engine

for better jump support. Some flow control support added too (but not
complete).


sql/lex.h:
  Added more keywords for embedded SQL.
sql/sp_head.cc:
  Fixed bugs in the parameter evaluation.
  Modified execute() for better jump support.
  Added jump instruction and backpatch support.
sql/sp_head.h:
  Fixed bugs in the parameter evaluation.
  Modified execute() for better jump support.
  Added jump instruction and backpatch support.
sql/sp_pcontext.cc:
  Added label support.
sql/sp_pcontext.h:
  Added label support.
sql/sql_yacc.yy:
  Outlined flow control constructs (parses, but nothing generated yet).
parent 20cd3f27
......@@ -59,6 +59,7 @@ static SYMBOL symbols[] = {
{ "ANY", SYM(ANY_SYM),0,0},
{ "AS", SYM(AS),0,0},
{ "ASC", SYM(ASC),0,0},
{ "ASENSITIVE", SYM(ASENSITIVE_SYM),0,0},
{ "AVG", SYM(AVG_SYM),0,0},
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0},
{ "AUTO_INCREMENT", SYM(AUTO_INC),0,0},
......@@ -107,6 +108,7 @@ static SYMBOL symbols[] = {
{ "CURRENT_DATE", SYM(CURDATE),0,0},
{ "CURRENT_TIME", SYM(CURTIME),0,0},
{ "CURRENT_TIMESTAMP", SYM(NOW_SYM),0,0},
{ "CURSOR", SYM(CURSOR_SYM),0,0},
{ "DATA", SYM(DATA_SYM),0,0},
{ "DATABASE", SYM(DATABASE),0,0},
{ "DATABASES", SYM(DATABASES),0,0},
......@@ -141,6 +143,7 @@ static SYMBOL symbols[] = {
{ "ERRORS", SYM(ERRORS),0,0},
{ "END", SYM(END),0,0},
{ "ELSE", SYM(ELSE),0,0},
{ "ELSEIF", SYM(ELSEIF_SYM),0,0},
{ "ESCAPE", SYM(ESCAPE_SYM),0,0},
{ "ESCAPED", SYM(ESCAPED),0,0},
{ "ENABLE", SYM(ENABLE_SYM),0,0},
......@@ -196,6 +199,7 @@ static SYMBOL symbols[] = {
{ "INNOBASE", SYM(INNOBASE_SYM),0,0},
{ "INNODB", SYM(INNOBASE_SYM),0,0},
{ "INOUT", SYM(INOUT_SYM),0,0},
{ "INSENSITIVE", SYM(INSENSITIVE_SYM),0,0},
{ "INSERT", SYM(INSERT),0,0},
{ "INSERT_METHOD", SYM(INSERT_METHOD),0,0},
{ "INT", SYM(INT_SYM),0,0},
......@@ -213,12 +217,14 @@ static SYMBOL symbols[] = {
{ "ISOLATION", SYM(ISOLATION),0,0},
{ "ISAM", SYM(ISAM_SYM),0,0},
{ "ISSUER", SYM(ISSUER_SYM),0,0},
{ "ITERATE", SYM(ITERATE_SYM),0,0},
{ "JOIN", SYM(JOIN_SYM),0,0},
{ "KEY", SYM(KEY_SYM),0,0},
{ "KEYS", SYM(KEYS),0,0},
{ "KILL", SYM(KILL_SYM),0,0},
{ "LAST", SYM(LAST_SYM),0,0},
{ "LEADING", SYM(LEADING),0,0},
{ "LEAVE", SYM(LEAVE_SYM),0,0},
{ "LEFT", SYM(LEFT),0,0},
{ "LEVEL", SYM(LEVEL_SYM),0,0},
{ "LIKE", SYM(LIKE),0,0},
......@@ -233,6 +239,7 @@ static SYMBOL symbols[] = {
{ "LOGS", SYM(LOGS_SYM),0,0},
{ "LONG", SYM(LONG_SYM),0,0},
{ "LONGBLOB", SYM(LONGBLOB),0,0},
{ "LOOP", SYM(LOOP_SYM),0,0},
{ "LONGTEXT", SYM(LONGTEXT),0,0},
{ "LOW_PRIORITY", SYM(LOW_PRIORITY),0,0},
{ "MASTER", SYM(MASTER_SYM),0,0},
......@@ -313,6 +320,7 @@ static SYMBOL symbols[] = {
{ "REPEATABLE", SYM(REPEATABLE_SYM),0,0},
{ "REQUIRE", SYM(REQUIRE_SYM),0,0},
{ "RESET", SYM(RESET_SYM),0,0},
{ "UNTIL", SYM(UNTIL_SYM),0,0},
{ "USER_RESOURCES", SYM(RESOURCES),0,0},
{ "RESTORE", SYM(RESTORE_SYM),0,0},
{ "RESTRICT", SYM(RESTRICT),0,0},
......@@ -327,6 +335,7 @@ static SYMBOL symbols[] = {
{ "RTREE", SYM(RTREE_SYM),0,0},
{ "SECOND", SYM(SECOND_SYM),0,0},
{ "SELECT", SYM(SELECT_SYM),0,0},
{ "SENSITIVE", SYM(SENSITIVE_SYM),0,0},
{ "SERIAL", SYM(SERIAL_SYM),0,0},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
{ "SESSION", SYM(SESSION_SYM),0,0},
......@@ -401,6 +410,7 @@ static SYMBOL symbols[] = {
{ "WRITE", SYM(WRITE_SYM),0,0},
{ "WHEN", SYM(WHEN_SYM),0,0},
{ "WHERE", SYM(WHERE),0,0},
{ "WHILE", SYM(WHILE_SYM),0,0},
{ "XOR", SYM(XOR),0,0},
{ "X509", SYM(X509_SYM),0,0},
{ "YEAR", SYM(YEAR_SYM),0,0},
......
......@@ -59,9 +59,9 @@ eval_func_item(Item *it, enum enum_field_types type)
{
char buffer[MAX_FIELD_WIDTH];
String tmp(buffer, sizeof(buffer), default_charset_info);
String *s= it->val_str(&tmp);
(void)it->val_str(&tmp);
it= new Item_string(buffer, sizeof(buffer), default_charset_info);
it= new Item_string(s->c_ptr_quick(), s->length(), default_charset_info);
break;
}
case MYSQL_TYPE_NULL:
......@@ -149,15 +149,21 @@ sp_head::execute(THD *thd)
{
sp_pvar_t *pvar = pctx->find_pvar(i);
// QQ Passing an argument is, in a sense, a "SET". We have to evaluate
// any expression at this point.
nctx->push_item(it->this_item());
// Note: If it's OUT or INOUT, it must be a variable.
// QQ: Need to handle "global" user/host variables too!!!
if (!pvar || pvar->mode == sp_param_in)
nctx->set_oindex(i, -1);
if (! pvar)
nctx->set_oindex(i, -1); // Shouldn't happen
else
nctx->set_oindex(i, static_cast<Item_splocal *>(it)->get_offset());
{
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.
// QQ: Need to handle "global" user/host variables too!!!
if (pvar->mode == sp_param_in)
nctx->set_oindex(i, -1); // IN
else // OUT or INOUT
nctx->set_oindex(i, static_cast<Item_splocal *>(it)->get_offset());
}
}
// 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,
......@@ -176,14 +182,12 @@ sp_head::execute(THD *thd)
while (ret == 0)
{
int offset;
sp_instr *i;
i = get_instr(ip); // Returns NULL when we're done.
if (i == NULL)
break;
ret= i->execute(thd, &offset);
ip += offset;
ret= i->execute(thd, &ip);
}
thd->net.no_send_ok= nsok;
......@@ -250,6 +254,27 @@ sp_head::restore_lex(THD *thd)
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
// 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
......@@ -350,12 +375,13 @@ sp_drop(THD *thd, char *name, uint namelen)
}
// ------------------------------------------------------------------
//
// sp_instr_stmt
//
int
sp_instr_stmt::execute(THD *thd, int *offsetp)
sp_instr_stmt::execute(THD *thd, uint *nextp)
{
LEX olex; // The other lex
......@@ -368,7 +394,7 @@ sp_instr_stmt::execute(THD *thd, int *offsetp)
memcpy(&thd->lex, &olex, sizeof(LEX)); // Restore the other lex
*offsetp = 1;
*nextp = m_ip+1;
return 0;
}
......@@ -376,9 +402,41 @@ sp_instr_stmt::execute(THD *thd, int *offsetp)
// sp_instr_set
//
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));
*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;
}
......@@ -72,6 +72,12 @@ class sp_head : public Sql_alloc
void
restore_lex(THD *thd);
void
push_backpatch(uint ip);
void
backpatch(uint dest);
private:
Item_string *m_name;
......@@ -79,6 +85,7 @@ class sp_head : public Sql_alloc
LEX *m_mylex; // My own lex
LEX m_lex; // Temp. store for the other lex
DYNAMIC_ARRAY m_instr; // The "instructions"
List<uint> m_backpatch; // Instructions needing backpaching
inline sp_instr *
get_instr(uint i)
......@@ -106,6 +113,10 @@ int
sp_drop(THD *thd, char *name, uint namelen);
//
// "Instructions"...
//
class sp_instr : public Sql_alloc
{
sp_instr(const sp_instr &); /* Prevent use of these */
......@@ -114,24 +125,28 @@ class sp_instr : public Sql_alloc
public:
// Should give each a name or type code for debugging purposes?
sp_instr()
: Sql_alloc()
sp_instr(uint ip)
: Sql_alloc(), m_ip(ip)
{}
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.)
// Execute this instrution. '*nextp' will be set to the index of the next
// instruction to execute. (For most instruction this will be the
// instruction following this one.)
// Returns 0 on success, non-zero if some error occured.
virtual int
execute(THD *thd, int *offsetp)
execute(THD *thd, uint *nextp)
{ // Default is a no-op.
*offsetp = 1; // Next instruction
*nextp = m_ip+1; // Next instruction
return 0;
}
protected:
uint m_ip; // My index
}; // class sp_instr : public Sql_alloc
......@@ -145,14 +160,14 @@ class sp_instr_stmt : public sp_instr
public:
sp_instr_stmt()
: sp_instr()
sp_instr_stmt(uint ip)
: sp_instr(ip)
{}
virtual ~sp_instr_stmt()
{}
virtual int execute(THD *thd, int *offsetp);
virtual int execute(THD *thd, uint *nextp);
inline void
set_lex(LEX *lex)
......@@ -180,21 +195,114 @@ class sp_instr_set : public sp_instr
public:
sp_instr_set(uint offset, Item *val, enum enum_field_types type)
: sp_instr(), m_offset(offset), m_value(val), m_type(type)
sp_instr_set(uint ip, uint offset, Item *val, enum enum_field_types type)
: sp_instr(ip), m_offset(offset), m_value(val), m_type(type)
{}
virtual ~sp_instr_set()
{}
virtual int execute(THD *thd, int *offsetp);
virtual int execute(THD *thd, uint *nextp);
private:
uint m_offset;
uint m_offset; // Frame offset
Item *m_value;
enum enum_field_types m_type; // The declared type
}; // 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_ */
......@@ -24,14 +24,16 @@
#include "mysql_priv.h"
#include "sp_pcontext.h"
#include "sp_head.h"
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 = (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));
m_label.empty();
}
void
......@@ -89,3 +91,41 @@ sp_pcontext::push(LEX_STRING *name, enum enum_field_types type,
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
my_bool isset;
} sp_pvar_t;
typedef struct
{
char *name;
uint ip; // Instruction index
} sp_label_t;
class sp_pcontext : public Sql_alloc
{
sp_pcontext(const sp_pcontext &); /* Prevent use of these */
......@@ -89,6 +95,7 @@ class sp_pcontext : public Sql_alloc
void
push(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode);
// Pop the last 'num' slots of the frame
inline void
pop(uint num = 1)
{
......@@ -109,6 +116,21 @@ class sp_pcontext : public Sql_alloc
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:
uint m_params; // The number of parameters
......@@ -121,6 +143,9 @@ class sp_pcontext : public Sql_alloc
void
grow();
List<sp_label_t> m_label; // The label list
uint m_genlab; // Gen. label counter
}; // class sp_pcontext : public Sql_alloc
......
......@@ -526,6 +526,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SQL_SMALL_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. */
%token SPSET_SYM
......@@ -680,7 +690,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
statement
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 <NONE>
......@@ -906,7 +916,7 @@ create:
{
Lex->spcont->set_params();
}
sp_proc_body
sp_proc_stmt
{
Lex->sql_command= SQLCOM_CREATE_PROCEDURE;
}
......@@ -974,26 +984,9 @@ sp_opt_locator:
| 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_proc_stmt ';'
| sp_proc_stmts sp_proc_stmt ';'
;
sp_decls:
......@@ -1037,14 +1030,69 @@ sp_decl_idents:
/* Dummy for the spset thing. Will go away when the SET problem is fixed. */
sp_proc_stmt:
{
Lex->sphead->reset_lex(YYTHD);
}
statement
{
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);
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
local SP variables as well. */
......@@ -1059,7 +1107,8 @@ sp_proc_stmt:
else
{
/* 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);
spv->isset= TRUE;
......@@ -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:
'(' field_list ')' 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