summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/Makefile.am4
-rw-r--r--sql/item.h5
-rw-r--r--sql/lex.h5
-rw-r--r--sql/sp.cc119
-rw-r--r--sql/sp.h33
-rw-r--r--sql/sp_head.cc155
-rw-r--r--sql/sp_head.h24
-rw-r--r--sql/sp_pcontext.h6
-rw-r--r--sql/sql_parse.cc1
-rw-r--r--sql/sql_yacc.yy65
10 files changed, 239 insertions, 178 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 1cdfc05ffdc..116c094aa04 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -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)
diff --git a/sql/item.h b/sql/item.h
index bffb9212e3d..366eb8f2e32 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -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
diff --git a/sql/lex.h b/sql/lex.h
index 829c16a3b74..606bb0eaf6c 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -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},
diff --git a/sql/sp.cc b/sql/sp.cc
new file mode 100644
index 00000000000..caeb01200ff
--- /dev/null
+++ b/sql/sp.cc
@@ -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;
+}
diff --git a/sql/sp.h b/sql/sp.h
new file mode 100644
index 00000000000..cb3343a4e92
--- /dev/null
+++ b/sql/sp.h
@@ -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_ */
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index ed93f005db3..8025fe3ef4c 100644
--- a/sql/sp_head.cc
+++ b/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)
-{
- 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
-// course.)
-sp_head *
-sp_find(THD *thd, Item_string *iname)
+sp_head::backpatch()
{
- 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;
-}
+ sp_instr *ip;
+ uint dest= instructions();
+ List_iterator_fast<sp_instr> li(m_backpatch);
-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)))
+ while ((ip= li++))
{
- ret= -1;
- goto done;
- }
-
- restore_record(table, 2); // Get default values for fields
+ sp_instr_jump *i= static_cast<sp_instr_jump *>(ip);
- 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));
+ i->set_destination(dest);
}
- 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)
{
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 53130bffdf1..87f2b78b9fd 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -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)
@@ -100,20 +100,6 @@ private:
//
-// 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
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 8a37adcf427..7c8e2ba0c43 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -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()
{
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index fba726c95b6..ac18b3369ac 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -28,6 +28,7 @@
#endif
#include "sp_head.h"
+#include "sp.h"
#ifdef HAVE_OPENSSL
/*
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index bc19560ea77..30f9fe97ec5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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: