mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
Moved create/find/drop functions to a separate files (sp.cc,sp.h).
Fixed backpatching of forward jumps. Implemented LOOP, WHILE, REPEAT (temporarily known as SPREPEAT). Known bug: Expression evaluation still not quite ok (e.g. "x > 0"), which is why IF and CASE is not yet implemented. sql/Makefile.am: Added new sp.h/sp.cc file. sql/item.h: New deferred result_type() method in Item_splocal. sql/lex.h: Temporary fix until REPEAT conflict is solved. Use SPREPEAT for now. sql/sp_head.cc: Moved create/find/drop functions to sp.cc. Fixed the backpatch stuff. (Also removed some dead code and updated comments.) sql/sp_head.h: Moved create/find/drop declarations to sp.h. Fixed the backpatch stuff. sql/sp_pcontext.h: New method: last_label(). sql/sql_parse.cc: Include sp.h. sql/sql_yacc.yy: Fixed backpatching of forward jumps. Implemented LOOP, WHILE, and REPEAT. (Note: SPREPEAT for now.)
This commit is contained in:
parent
37ce17e2cd
commit
b1b6227485
10 changed files with 239 additions and 178 deletions
|
@ -58,7 +58,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
|||
log_event.h mini_client.h sql_repl.h slave.h \
|
||||
stacktrace.h sql_sort.h sql_cache.h set_var.h \
|
||||
spatial.h gstream.h sp_head.h sp_pcontext.h \
|
||||
sp_rcontext.h
|
||||
sp_rcontext.h sp.h
|
||||
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
|
||||
item.cc item_sum.cc item_buff.cc item_func.cc \
|
||||
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
|
||||
|
@ -87,7 +87,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
|
|||
mini_client.cc mini_client_errors.c \
|
||||
stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\
|
||||
gstream.cc spatial.cc sql_help.cc \
|
||||
sp_head.cc sp_pcontext.cc
|
||||
sp_head.cc sp_pcontext.cc sp.cc
|
||||
gen_lex_hash_SOURCES = gen_lex_hash.cc
|
||||
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
|
||||
|
||||
|
|
|
@ -126,6 +126,11 @@ public:
|
|||
return m_offset;
|
||||
}
|
||||
|
||||
virtual Item_result result_type() const
|
||||
{
|
||||
return this_const_item()->result_type();
|
||||
}
|
||||
|
||||
// Abstract methods inherited from Item. Just defer the call to
|
||||
// the item in the frame
|
||||
inline enum Type type() const
|
||||
|
|
|
@ -317,10 +317,10 @@ static SYMBOL symbols[] = {
|
|||
{ "REPAIR", SYM(REPAIR),0,0},
|
||||
{ "REPLACE", SYM(REPLACE),0,0},
|
||||
{ "REPLICATION", SYM(REPLICATION),0,0},
|
||||
{ "SPREPEAT", SYM(SPREPEAT_SYM),0,0}, /* QQ Temp. until conflict solved */
|
||||
{ "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},
|
||||
|
@ -351,7 +351,7 @@ static SYMBOL symbols[] = {
|
|||
{ "SONAME", SYM(UDF_SONAME_SYM),0,0},
|
||||
{ "SPATIAL", SYM(SPATIAL_SYM),0,0},
|
||||
{ "SPECIFIC", SYM(SPECIFIC_SYM),0,0},
|
||||
{ "SPSET", SYM(SPSET_SYM),0,0},
|
||||
{ "SPSET", SYM(SPSET_SYM),0,0}, /* Temp. until SET parsing solved. */
|
||||
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
|
||||
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
|
||||
{ "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
|
||||
|
@ -392,6 +392,7 @@ static SYMBOL symbols[] = {
|
|||
{ "UNIQUE", SYM(UNIQUE_SYM),0,0},
|
||||
{ "UNLOCK", SYM(UNLOCK_SYM),0,0},
|
||||
{ "UNSIGNED", SYM(UNSIGNED),0,0},
|
||||
{ "UNTIL", SYM(UNTIL_SYM),0,0},
|
||||
{ "USE", SYM(USE_SYM),0,0},
|
||||
{ "USE_FRM", SYM(USE_FRM),0,0},
|
||||
{ "USING", SYM(USING),0,0},
|
||||
|
|
119
sql/sp.cc
Normal file
119
sql/sp.cc
Normal file
|
@ -0,0 +1,119 @@
|
|||
/* 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 */
|
||||
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include "sp.h"
|
||||
#include "sp_head.h"
|
||||
|
||||
// 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
|
||||
// course.)
|
||||
sp_head *
|
||||
sp_find(THD *thd, Item_string *iname)
|
||||
{
|
||||
extern int yyparse(void *thd);
|
||||
LEX *tmplex;
|
||||
TABLE *table;
|
||||
TABLE_LIST tables;
|
||||
const char *defstr;
|
||||
String *name;
|
||||
sp_head *sp = NULL;
|
||||
|
||||
name = iname->const_string();
|
||||
memset(&tables, 0, sizeof(tables));
|
||||
tables.db= (char*)"mysql";
|
||||
tables.real_name= tables.alias= (char*)"proc";
|
||||
if (! (table= open_ltable(thd, &tables, TL_READ)))
|
||||
return NULL;
|
||||
|
||||
if (table->file->index_read_idx(table->record[0], 0,
|
||||
(byte*)name->c_ptr(), name->length(),
|
||||
HA_READ_KEY_EXACT))
|
||||
goto done;
|
||||
|
||||
if ((defstr= get_field(&thd->mem_root, table, 1)) == NULL)
|
||||
goto done;
|
||||
|
||||
// QQ Set up our own mem_root here???
|
||||
tmplex= lex_start(thd, (uchar*)defstr, strlen(defstr));
|
||||
if (yyparse(thd) || thd->fatal_error || tmplex->sphead == NULL)
|
||||
goto done; // Error
|
||||
else
|
||||
sp = tmplex->sphead;
|
||||
|
||||
done:
|
||||
if (table)
|
||||
close_thread_tables(thd);
|
||||
return sp;
|
||||
}
|
||||
|
||||
int
|
||||
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen)
|
||||
{
|
||||
int ret= 0;
|
||||
TABLE *table;
|
||||
TABLE_LIST tables;
|
||||
|
||||
memset(&tables, 0, sizeof(tables));
|
||||
tables.db= (char*)"mysql";
|
||||
tables.real_name= tables.alias= (char*)"proc";
|
||||
/* Allow creation of procedures even if we can't open proc table */
|
||||
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
|
||||
{
|
||||
ret= -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
restore_record(table, 2); // Get default values for fields
|
||||
|
||||
table->field[0]->store(name, namelen, default_charset_info);
|
||||
table->field[1]->store(def, deflen, default_charset_info);
|
||||
|
||||
ret= table->file->write_row(table->record[0]);
|
||||
|
||||
done:
|
||||
close_thread_tables(thd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
sp_drop(THD *thd, char *name, uint namelen)
|
||||
{
|
||||
TABLE *table;
|
||||
TABLE_LIST tables;
|
||||
|
||||
tables.db= (char *)"mysql";
|
||||
tables.real_name= tables.alias= (char *)"proc";
|
||||
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
|
||||
goto err;
|
||||
if (! table->file->index_read_idx(table->record[0], 0,
|
||||
(byte *)name, namelen,
|
||||
HA_READ_KEY_EXACT))
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error= table->file->delete_row(table->record[0])))
|
||||
table->file->print_error(error, MYF(0));
|
||||
}
|
||||
close_thread_tables(thd);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
close_thread_tables(thd);
|
||||
return -1;
|
||||
}
|
33
sql/sp.h
Normal file
33
sql/sp.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* -*- 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_H_
|
||||
#define _SP_H_
|
||||
|
||||
//
|
||||
// Finds 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);
|
||||
|
||||
#endif /* _SP_H_ */
|
155
sql/sp_head.cc
155
sql/sp_head.cc
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "mysql_priv.h"
|
||||
#include "sp_head.h"
|
||||
#include "sp.h"
|
||||
#include "sp_pcontext.h"
|
||||
#include "sp_rcontext.h"
|
||||
|
||||
|
@ -31,9 +32,7 @@ eval_func_item(Item *it, enum enum_field_types type)
|
|||
{
|
||||
it= it->this_item();
|
||||
|
||||
/* QQ Which way do we do this? Or is there some even better way? */
|
||||
#if 1
|
||||
/* QQ Obey the declared type of the variable */
|
||||
/* QQ How do we do this? Is there some better way? */
|
||||
switch (type)
|
||||
{
|
||||
case MYSQL_TYPE_TINY:
|
||||
|
@ -77,30 +76,7 @@ eval_func_item(Item *it, enum enum_field_types type)
|
|||
/* QQ Don't know what to do with the rest. */
|
||||
break;
|
||||
}
|
||||
#else
|
||||
/* QQ This looks simpler, but is wrong? It disregards the variable's type. */
|
||||
switch (it->result_type())
|
||||
{
|
||||
case REAL_RESULT:
|
||||
it= new Item_real(it->val());
|
||||
break;
|
||||
case INT_RESULT:
|
||||
it= new Item_int(it->val_int());
|
||||
break;
|
||||
case STRING_RESULT:
|
||||
{
|
||||
char buffer[MAX_FIELD_WIDTH];
|
||||
String tmp(buffer, sizeof(buffer), default_charset_info);
|
||||
|
||||
(void)it->val_str(&tmp);
|
||||
it= new Item_string(buffer, sizeof(buffer), default_charset_info);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* QQ Don't know what to do with the rest. */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return it;
|
||||
}
|
||||
|
||||
|
@ -113,6 +89,7 @@ sp_head::sp_head(LEX_STRING *name, LEX *lex)
|
|||
m_defstr= new Item_string(dstr, lex->end_of_query - lex->buf,
|
||||
default_charset_info);
|
||||
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
|
||||
m_backpatch.empty();
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -144,7 +121,7 @@ sp_head::execute(THD *thd)
|
|||
Item *it = li++; // Skip first one, it's the procedure name
|
||||
|
||||
nctx = new sp_rcontext(csize);
|
||||
// QQ: No error checking whatsoever right now
|
||||
// QQ: No error checking whatsoever right now. Should do type checking?
|
||||
for (i = 0 ; (it= li++) && i < params ; i++)
|
||||
{
|
||||
sp_pvar_t *pvar = pctx->find_pvar(i);
|
||||
|
@ -168,7 +145,7 @@ sp_head::execute(THD *thd)
|
|||
// 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,
|
||||
// so we set it to NULL for now. It's an error to refer to an
|
||||
// unassigned variable (which should be detected by the parser).
|
||||
// unassigned variable anyway (which should be detected by the parser).
|
||||
for (; i < csize ; i++)
|
||||
nctx->push_item(NULL);
|
||||
thd->spcont= nctx;
|
||||
|
@ -212,6 +189,7 @@ sp_head::execute(THD *thd)
|
|||
}
|
||||
|
||||
|
||||
// Reset lex during parsing, before we parse a sub statement.
|
||||
void
|
||||
sp_head::reset_lex(THD *thd)
|
||||
{
|
||||
|
@ -244,6 +222,7 @@ sp_head::reset_lex(THD *thd)
|
|||
thd->lex.auxilliary_table_list.empty();
|
||||
}
|
||||
|
||||
// Restore lex during parsing, after we have parsed a sub statement.
|
||||
void
|
||||
sp_head::restore_lex(THD *thd)
|
||||
{
|
||||
|
@ -255,123 +234,25 @@ sp_head::restore_lex(THD *thd)
|
|||
}
|
||||
|
||||
void
|
||||
sp_head::push_backpatch(uint ip)
|
||||
sp_head::push_backpatch(sp_instr *i)
|
||||
{
|
||||
(void)m_backpatch.push_front(&ip);
|
||||
(void)m_backpatch.push_front(i);
|
||||
}
|
||||
|
||||
void
|
||||
sp_head::backpatch(uint dest)
|
||||
sp_head::backpatch()
|
||||
{
|
||||
while (! m_backpatch.is_empty())
|
||||
sp_instr *ip;
|
||||
uint dest= instructions();
|
||||
List_iterator_fast<sp_instr> li(m_backpatch);
|
||||
|
||||
while ((ip= li++))
|
||||
{
|
||||
uint *ip= m_backpatch.pop();
|
||||
sp_instr_jump *i= static_cast<sp_instr_jump *>(get_instr(*ip));
|
||||
sp_instr_jump *i= static_cast<sp_instr_jump *>(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
|
||||
// course.)
|
||||
sp_head *
|
||||
sp_find(THD *thd, Item_string *iname)
|
||||
{
|
||||
extern int yyparse(void *thd);
|
||||
LEX *tmplex;
|
||||
TABLE *table;
|
||||
TABLE_LIST tables;
|
||||
const char *defstr;
|
||||
String *name;
|
||||
sp_head *sp = NULL;
|
||||
|
||||
name = iname->const_string();
|
||||
memset(&tables, 0, sizeof(tables));
|
||||
tables.db= (char*)"mysql";
|
||||
tables.real_name= tables.alias= (char*)"proc";
|
||||
if (! (table= open_ltable(thd, &tables, TL_READ)))
|
||||
return NULL;
|
||||
|
||||
if (table->file->index_read_idx(table->record[0], 0,
|
||||
(byte*)name->c_ptr(), name->length(),
|
||||
HA_READ_KEY_EXACT))
|
||||
goto done;
|
||||
|
||||
if ((defstr= get_field(&thd->mem_root, table, 1)) == NULL)
|
||||
goto done;
|
||||
|
||||
// QQ Set up our own mem_root here???
|
||||
tmplex= lex_start(thd, (uchar*)defstr, strlen(defstr));
|
||||
if (yyparse(thd) || thd->fatal_error || tmplex->sphead == NULL)
|
||||
goto done; // Error
|
||||
else
|
||||
sp = tmplex->sphead;
|
||||
|
||||
done:
|
||||
if (table)
|
||||
close_thread_tables(thd);
|
||||
return sp;
|
||||
}
|
||||
|
||||
int
|
||||
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen)
|
||||
{
|
||||
int ret= 0;
|
||||
TABLE *table;
|
||||
TABLE_LIST tables;
|
||||
|
||||
memset(&tables, 0, sizeof(tables));
|
||||
tables.db= (char*)"mysql";
|
||||
tables.real_name= tables.alias= (char*)"proc";
|
||||
/* Allow creation of procedures even if we can't open proc table */
|
||||
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
|
||||
{
|
||||
ret= -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
restore_record(table, 2); // Get default values for fields
|
||||
|
||||
table->field[0]->store(name, namelen, default_charset_info);
|
||||
table->field[1]->store(def, deflen, default_charset_info);
|
||||
|
||||
ret= table->file->write_row(table->record[0]);
|
||||
|
||||
done:
|
||||
close_thread_tables(thd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
sp_drop(THD *thd, char *name, uint namelen)
|
||||
{
|
||||
TABLE *table;
|
||||
TABLE_LIST tables;
|
||||
|
||||
tables.db= (char *)"mysql";
|
||||
tables.real_name= tables.alias= (char *)"proc";
|
||||
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
|
||||
goto err;
|
||||
if (! table->file->index_read_idx(table->record[0], 0,
|
||||
(byte *)name, namelen,
|
||||
HA_READ_KEY_EXACT))
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error= table->file->delete_row(table->record[0])))
|
||||
table->file->print_error(error, MYF(0));
|
||||
}
|
||||
close_thread_tables(thd);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
close_thread_tables(thd);
|
||||
return -1;
|
||||
m_backpatch.empty();
|
||||
}
|
||||
|
||||
|
||||
|
@ -412,7 +293,6 @@ sp_instr_set::execute(THD *thd, uint *nextp)
|
|||
//
|
||||
// sp_instr_jump_if
|
||||
//
|
||||
|
||||
int
|
||||
sp_instr_jump_if::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
|
@ -428,7 +308,6 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp)
|
|||
//
|
||||
// sp_instr_jump_if_not
|
||||
//
|
||||
|
||||
int
|
||||
sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
|
|
|
@ -73,10 +73,10 @@ public:
|
|||
restore_lex(THD *thd);
|
||||
|
||||
void
|
||||
push_backpatch(uint ip);
|
||||
push_backpatch(sp_instr *i);
|
||||
|
||||
void
|
||||
backpatch(uint dest);
|
||||
backpatch();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -85,7 +85,7 @@ private:
|
|||
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
|
||||
List<sp_instr> m_backpatch; // Instructions needing backpaching
|
||||
|
||||
inline sp_instr *
|
||||
get_instr(uint i)
|
||||
|
@ -99,20 +99,6 @@ private:
|
|||
}; // 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);
|
||||
|
||||
|
||||
//
|
||||
// "Instructions"...
|
||||
//
|
||||
|
@ -243,7 +229,7 @@ public:
|
|||
m_dest= dest;
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
|
||||
int m_dest; // Where we will go
|
||||
|
||||
|
@ -272,7 +258,6 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
int m_dest; // Where we will go
|
||||
Item *m_expr; // The condition
|
||||
|
||||
}; // class sp_instr_jump_if : public sp_instr_jump
|
||||
|
@ -300,7 +285,6 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
int m_dest; // Where we will go
|
||||
Item *m_expr; // The condition
|
||||
|
||||
}; // class sp_instr_jump_if_not : public sp_instr_jump
|
||||
|
|
|
@ -125,6 +125,12 @@ class sp_pcontext : public Sql_alloc
|
|||
sp_label_t *
|
||||
find_label(char *name);
|
||||
|
||||
inline sp_label_t *
|
||||
last_label()
|
||||
{
|
||||
return m_label.head();
|
||||
}
|
||||
|
||||
inline void
|
||||
pop_label()
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#endif
|
||||
|
||||
#include "sp_head.h"
|
||||
#include "sp.h"
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
/*
|
||||
|
|
|
@ -531,6 +531,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||
%token ITERATE_SYM
|
||||
%token LEAVE_SYM
|
||||
%token LOOP_SYM
|
||||
/* QQ This is temporary, until the REPEAT conflict is solved. */
|
||||
%token SPREPEAT_SYM
|
||||
%token UNTIL_SYM
|
||||
%token WHILE_SYM
|
||||
%token ASENSITIVE_SYM
|
||||
|
@ -1053,8 +1055,10 @@ sp_proc_stmt:
|
|||
}
|
||||
sp_unlabeled_control
|
||||
{
|
||||
/* QQ backpatch here */
|
||||
Lex->spcont->pop_label();
|
||||
LEX *lex= Lex;
|
||||
|
||||
lex->spcont->pop_label();
|
||||
lex->sphead->backpatch();
|
||||
}
|
||||
| LEAVE_SYM IDENT
|
||||
{
|
||||
|
@ -1068,10 +1072,9 @@ sp_proc_stmt:
|
|||
}
|
||||
else
|
||||
{
|
||||
uint ip= lex->sphead->instructions();
|
||||
sp_instr_jump *i= new sp_instr_jump(ip, 0);
|
||||
sp_instr_jump *i= new sp_instr_jump(lex->sphead->instructions());
|
||||
|
||||
lex->sphead->push_backpatch(ip);
|
||||
lex->sphead->push_backpatch(i); /* Jumping forward */
|
||||
lex->sphead->add_instr(i);
|
||||
}
|
||||
}
|
||||
|
@ -1088,7 +1091,7 @@ sp_proc_stmt:
|
|||
else
|
||||
{
|
||||
uint ip= lex->sphead->instructions();
|
||||
sp_instr_jump *i= new sp_instr_jump(ip, lab->ip);
|
||||
sp_instr_jump *i= new sp_instr_jump(ip, lab->ip); /* Jump back */
|
||||
|
||||
lex->sphead->add_instr(i);
|
||||
}
|
||||
|
@ -1148,29 +1151,59 @@ sp_labeled_control:
|
|||
}
|
||||
else
|
||||
{
|
||||
/* QQ backpatch here */
|
||||
lex->spcont->pop_label();
|
||||
lex->sphead->backpatch();
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
sp_unlabeled_control:
|
||||
begin
|
||||
BEGIN_SYM
|
||||
sp_decls
|
||||
sp_proc_stmts
|
||||
END
|
||||
{
|
||||
{ /* QQ This is just a dummy for grouping declarations and statements
|
||||
together. No [[NOT] ATOMIC] yet, and we need to figure out how
|
||||
make it coexist with the existing BEGIN COMMIT/ROLLBACK. */
|
||||
Lex->spcont->pop($2);
|
||||
}
|
||||
| LOOP_SYM
|
||||
sp_proc_stmts
|
||||
END LOOP_SYM
|
||||
sp_proc_stmts END LOOP_SYM
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
uint ip= lex->sphead->instructions();
|
||||
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
|
||||
sp_instr_jump *i = new sp_instr_jump(ip, lab->ip);
|
||||
|
||||
lex->sphead->add_instr(i);
|
||||
}
|
||||
| WHILE_SYM expr DO_SYM
|
||||
sp_proc_stmts
|
||||
END WHILE_SYM
|
||||
| FUNC_ARG2 /* "REPEAT" actually... */
|
||||
sp_proc_stmts
|
||||
UNTIL_SYM expr END FUNC_ARG2
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
uint ip= lex->sphead->instructions();
|
||||
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $2);
|
||||
|
||||
lex->sphead->push_backpatch(i); /* Jumping forward */
|
||||
lex->sphead->add_instr(i);
|
||||
}
|
||||
sp_proc_stmts END WHILE_SYM
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
uint ip= lex->sphead->instructions();
|
||||
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
|
||||
sp_instr_jump *i = new sp_instr_jump(ip, lab->ip);
|
||||
|
||||
lex->sphead->add_instr(i);
|
||||
}
|
||||
| SPREPEAT_SYM sp_proc_stmts UNTIL_SYM expr END SPREPEAT_SYM
|
||||
{ /* ^^ QQ temp. until conflict solved ^^ */
|
||||
LEX *lex= Lex;
|
||||
uint ip= lex->sphead->instructions();
|
||||
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
|
||||
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $4, lab->ip);
|
||||
|
||||
lex->sphead->add_instr(i);
|
||||
}
|
||||
;
|
||||
|
||||
create2:
|
||||
|
|
Loading…
Reference in a new issue