Commit 1604bea5 authored by pem@mysql.com's avatar pem@mysql.com

Merge

parents af76ac08 204aa972
...@@ -6,6 +6,7 @@ FROM=$USER@mysql.com ...@@ -6,6 +6,7 @@ FROM=$USER@mysql.com
INTERNALS=internals@lists.mysql.com INTERNALS=internals@lists.mysql.com
DOCS=docs-commit@mysql.com DOCS=docs-commit@mysql.com
LIMIT=10000 LIMIT=10000
REPOV=5.0
if [ "$REAL_EMAIL" = "" ] if [ "$REAL_EMAIL" = "" ]
then then
...@@ -27,15 +28,15 @@ CHANGESET=`bk -R prs -r+ -h -d':I:' ChangeSet` ...@@ -27,15 +28,15 @@ CHANGESET=`bk -R prs -r+ -h -d':I:' ChangeSet`
echo "Commit successful, notifying developers at $TO" echo "Commit successful, notifying developers at $TO"
( (
cat <<EOF cat <<EOF
List-ID: <bk.mysql-4.1> List-ID: <bk.mysql-$REPOV>
From: $FROM From: $FROM
To: $TO To: $TO
Subject: bk commit - 4.1 tree ($CHANGESET) Subject: bk commit - $REPOV tree ($CHANGESET)
EOF EOF
bk changes -v -r+ bk changes -v -r+
bk cset -r+ -d bk cset -r+ -d
) | head -n $LIMIT | /usr/sbin/sendmail -t ) | /usr/sbin/sendmail -t
#++ #++
# internals@ mail # internals@ mail
...@@ -43,13 +44,13 @@ EOF ...@@ -43,13 +44,13 @@ EOF
echo "Notifying internals list at $INTERNALS" echo "Notifying internals list at $INTERNALS"
( (
cat <<EOF cat <<EOF
List-ID: <bk.mysql-4.1> List-ID: <bk.mysql-$REPOV>
From: $FROM From: $FROM
To: $INTERNALS To: $INTERNALS
Subject: bk commit into 4.1 tree ($CHANGESET) Subject: bk commit into $REPOV tree ($CHANGESET)
Below is the list of changes that have just been committed into a local Below is the list of changes that have just been committed into a local
4.1 repository of $USER. When $USER does a push these changes will $REPOV repository of $USER. When $USER does a push these changes will
be propagated to the main repository and, within 24 hours after the be propagated to the main repository and, within 24 hours after the
push, to the public repository. push, to the public repository.
For information on how to access the public repository For information on how to access the public repository
...@@ -70,15 +71,15 @@ EOF ...@@ -70,15 +71,15 @@ EOF
echo "Notifying docs list at $DOCS" echo "Notifying docs list at $DOCS"
( (
cat <<EOF cat <<EOF
List-ID: <bk.mysql-4.1> List-ID: <bk.mysql-$REPOV>
From: $FROM From: $FROM
To: $DOCS To: $DOCS
Subject: bk commit - 4.1 tree (Manual) ($CHANGESET) Subject: bk commit - $REPOV tree (Manual) ($CHANGESET)
EOF EOF
bk changes -v -r+ bk changes -v -r+
bk cset -r+ -d bk cset -r+ -d
) | head -n $LIMIT | /usr/sbin/sendmail -t ) | /usr/sbin/sendmail -t
fi fi
else else
......
...@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. ...@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(sql/mysqld.cc) AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line! # The Docs Makefile.am parses this line!
AM_INIT_AUTOMAKE(mysql, 4.1.0-alpha) AM_INIT_AUTOMAKE(mysql, 5.0.0-alpha)
AM_CONFIG_HEADER(config.h) AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10 PROTOCOL_VERSION=10
......
...@@ -306,6 +306,18 @@ then ...@@ -306,6 +306,18 @@ then
c_c="$c_c comment='Column privileges';" c_c="$c_c comment='Column privileges';"
fi fi
if test ! -f $mdata/proc.frm
then
echo "Preparing proc table"
c_p="$c_p CREATE TABLE proc ("
c_p="$c_p name char(64) binary DEFAULT '' NOT NULL,"
c_p="$c_p body blob DEFAULT '' NOT NULL,"
c_p="$c_p PRIMARY KEY (name)"
c_p="$c_p )"
c_p="$c_p comment='Stored Procedures';"
fi
echo "Installing all prepared tables" echo "Installing all prepared tables"
if ( if (
cat << END_OF_DATA cat << END_OF_DATA
...@@ -324,6 +336,7 @@ $i_f ...@@ -324,6 +336,7 @@ $i_f
$c_t $c_t
$c_c $c_c
$c_p
END_OF_DATA END_OF_DATA
cat fill_func_tables.sql cat fill_func_tables.sql
) | eval "$execdir/mysqld $defaults --bootstrap --skip-grant-tables \ ) | eval "$execdir/mysqld $defaults --bootstrap --skip-grant-tables \
......
...@@ -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 sp.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 sp.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)
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <m_ctype.h> #include <m_ctype.h>
#include "my_dir.h" #include "my_dir.h"
#include <assert.h> #include <assert.h>
#include "sp_rcontext.h"
/***************************************************************************** /*****************************************************************************
** Item functions ** Item functions
...@@ -149,6 +150,24 @@ CHARSET_INFO * Item::thd_charset() const ...@@ -149,6 +150,24 @@ CHARSET_INFO * Item::thd_charset() const
return current_thd->variables.thd_charset; return current_thd->variables.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);
......
...@@ -97,6 +97,8 @@ class Item { ...@@ -97,6 +97,8 @@ class Item {
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 void set_outer_resolving() {} virtual void set_outer_resolving() {}
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; }
...@@ -110,6 +112,57 @@ class Item { ...@@ -110,6 +112,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);
}
};
class st_select_lex; class st_select_lex;
class Item_ident :public Item class Item_ident :public Item
{ {
......
...@@ -60,6 +60,7 @@ static SYMBOL symbols[] = { ...@@ -60,6 +60,7 @@ static SYMBOL symbols[] = {
{ "AS", SYM(AS),0,0}, { "AS", SYM(AS),0,0},
{ "ASC", SYM(ASC),0,0}, { "ASC", SYM(ASC),0,0},
{ "ASCII", SYM(ASCII_SYM),0,0}, { "ASCII", SYM(ASCII_SYM),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},
...@@ -80,6 +81,7 @@ static SYMBOL symbols[] = { ...@@ -80,6 +81,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},
...@@ -107,6 +109,7 @@ static SYMBOL symbols[] = { ...@@ -107,6 +109,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},
...@@ -118,6 +121,7 @@ static SYMBOL symbols[] = { ...@@ -118,6 +121,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},
...@@ -140,6 +144,7 @@ static SYMBOL symbols[] = { ...@@ -140,6 +144,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},
...@@ -194,6 +199,8 @@ static SYMBOL symbols[] = { ...@@ -194,6 +199,8 @@ 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},
{ "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},
...@@ -211,12 +218,14 @@ static SYMBOL symbols[] = { ...@@ -211,12 +218,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},
...@@ -231,6 +240,7 @@ static SYMBOL symbols[] = { ...@@ -231,6 +240,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},
...@@ -280,6 +290,7 @@ static SYMBOL symbols[] = { ...@@ -280,6 +290,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},
...@@ -307,6 +318,7 @@ static SYMBOL symbols[] = { ...@@ -307,6 +318,7 @@ static SYMBOL symbols[] = {
{ "REPAIR", SYM(REPAIR),0,0}, { "REPAIR", SYM(REPAIR),0,0},
{ "REPLACE", SYM(REPLACE),0,0}, { "REPLACE", SYM(REPLACE),0,0},
{ "REPLICATION", SYM(REPLICATION),0,0}, { "REPLICATION", SYM(REPLICATION),0,0},
{ "SPREPEAT", SYM(SPREPEAT_SYM),0,0}, /* QQ Temp. until conflict solved */
{ "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},
...@@ -324,6 +336,7 @@ static SYMBOL symbols[] = { ...@@ -324,6 +336,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},
...@@ -338,6 +351,8 @@ static SYMBOL symbols[] = { ...@@ -338,6 +351,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}, /* Temp. until SET parsing solved. */
{ "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},
...@@ -380,6 +395,7 @@ static SYMBOL symbols[] = { ...@@ -380,6 +395,7 @@ static SYMBOL symbols[] = {
{ "UNIQUE", SYM(UNIQUE_SYM),0,0}, { "UNIQUE", SYM(UNIQUE_SYM),0,0},
{ "UNLOCK", SYM(UNLOCK_SYM),0,0}, { "UNLOCK", SYM(UNLOCK_SYM),0,0},
{ "UNSIGNED", SYM(UNSIGNED),0,0}, { "UNSIGNED", SYM(UNSIGNED),0,0},
{ "UNTIL", SYM(UNTIL_SYM),0,0},
{ "USE", SYM(USE_SYM),0,0}, { "USE", SYM(USE_SYM),0,0},
{ "USE_FRM", SYM(USE_FRM),0,0}, { "USE_FRM", SYM(USE_FRM),0,0},
{ "USING", SYM(USING),0,0}, { "USING", SYM(USING),0,0},
...@@ -398,6 +414,7 @@ static SYMBOL symbols[] = { ...@@ -398,6 +414,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},
......
/* 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;
}
/* -*- 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_ */
/* 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
#include "mysql_priv.h"
#include "sp_head.h"
#include "sp.h"
#include "sp_pcontext.h"
#include "sp_rcontext.h"
/* Evaluate a (presumed) func item. Always returns an item, the parameter
** if nothing else.
*/
static Item *
eval_func_item(THD *thd, Item *it, enum enum_field_types type)
{
it= it->this_item();
if (it->fix_fields(thd, 0, NULL))
return it; // Shouldn't happen?
/* QQ How do we do this? Is there some better way? */
switch (type)
{
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_INT24:
it= new Item_int(it->val_int());
break;
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
it= new Item_real(it->val());
break;
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_NEWDATE:
{
char buffer[MAX_FIELD_WIDTH];
String tmp(buffer, sizeof(buffer), default_charset_info);
String *s= it->val_str(&tmp);
it= new Item_string(s->c_ptr_quick(), s->length(), default_charset_info);
break;
}
case MYSQL_TYPE_NULL:
it= new Item_null(); // A NULL is a NULL is a NULL...
break;
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_GEOMETRY:
/* QQ Don't know what to do with the rest. */
break;
}
return it;
}
sp_head::sp_head(LEX_STRING *name, LEX *lex)
: m_simple_case(FALSE)
{
const char *dstr = (const char*)lex->buf;
m_call_lex= lex;
m_name= new Item_string(name->str, name->length, default_charset_info);
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
sp_head::create(THD *thd)
{
String *name= m_name->const_string();
String *def= m_defstr->const_string();
return sp_create_procedure(thd,
name->c_ptr(), name->length(),
def->c_ptr(), def->length());
}
int
sp_head::execute(THD *thd)
{
int ret= 0;
sp_instr *p;
sp_pcontext *pctx = m_call_lex->spcont;
uint csize = pctx->max_framesize();
uint params = pctx->params();
sp_rcontext *octx = thd->spcont;
sp_rcontext *nctx = NULL;
if (csize > 0)
{
uint i;
List_iterator_fast<Item> li(m_call_lex->value_list);
Item *it = li++; // Skip first one, it's the procedure name
nctx = new sp_rcontext(csize);
// 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);
if (! pvar)
nctx->set_oindex(i, -1); // Shouldn't happen
else
{
if (pvar->mode == sp_param_out)
nctx->push_item(it->this_item()); // OUT
else
nctx->push_item(eval_func_item(thd, 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,
// so we set it to NULL for now. It's an error to refer to an
// unassigned variable anyway (which should be detected by the parser).
for (; i < csize ; i++)
nctx->push_item(NULL);
thd->spcont= nctx;
}
{ // Execute instructions...
uint ip= 0;
my_bool nsok= thd->net.no_send_ok;
thd->net.no_send_ok= TRUE; // Don't send_ok() during execution
while (ret == 0)
{
sp_instr *i;
i = get_instr(ip); // Returns NULL when we're done.
if (i == NULL)
break;
ret= i->execute(thd, &ip);
}
thd->net.no_send_ok= nsok;
}
// Don't copy back OUT values if we got an error
if (ret == 0 && csize > 0)
{
// Copy back all OUT or INOUT values to the previous frame
for (uint i = 0 ; i < params ; i++)
{
int oi = nctx->get_oindex(i);
if (oi >= 0)
octx->set_item(nctx->get_oindex(i), nctx->get_item(i));
}
thd->spcont= octx;
}
return ret;
}
// Reset lex during parsing, before we parse a sub statement.
void
sp_head::reset_lex(THD *thd)
{
memcpy(&m_lex, &thd->lex, sizeof(LEX)); // Save old one
/* Reset most stuff. The length arguments doesn't matter here. */
lex_start(thd, m_lex.buf, m_lex.end_of_query - m_lex.ptr);
/* We must reset ptr and end_of_query again */
thd->lex.ptr= m_lex.ptr;
thd->lex.end_of_query= m_lex.end_of_query;
/* And keep the SP stuff too */
thd->lex.sphead = m_lex.sphead;
thd->lex.spcont = m_lex.spcont;
/* Clear all lists. (QQ Why isn't this reset by lex_start()?).
We may be overdoing this, but we know for sure that value_list must
be cleared at least. */
thd->lex.col_list.empty();
thd->lex.ref_list.empty();
thd->lex.drop_list.empty();
thd->lex.alter_list.empty();
thd->lex.interval_list.empty();
thd->lex.users_list.empty();
thd->lex.columns.empty();
thd->lex.key_list.empty();
thd->lex.create_list.empty();
thd->lex.insert_list= NULL;
thd->lex.field_list.empty();
thd->lex.value_list.empty();
thd->lex.many_values.empty();
thd->lex.var_list.empty();
thd->lex.param_list.empty();
thd->lex.proc_list.empty();
thd->lex.auxilliary_table_list.empty();
}
// Restore lex during parsing, after we have parsed a sub statement.
void
sp_head::restore_lex(THD *thd)
{
// Update some state in the old one first
m_lex.ptr= thd->lex.ptr;
m_lex.next_state= thd->lex.next_state;
// Collect some data from the sub statement lex.
if (thd->lex.sql_command == SQLCOM_CALL)
{
// We know they are Item_strings (since we put them there ourselves)
// It would be slightly faster to keep the list sorted, but we need
// an "insert before" method to do that.
Item_string *proc= static_cast<Item_string*>(thd->lex.value_list.head());
String *snew= proc->val_str(NULL);
List_iterator_fast<Item_string> li(m_calls);
Item_string *it;
while ((it= li++))
{
String *sold= it->val_str(NULL);
if (stringcmp(snew, sold) == 0)
break;
}
if (! it)
m_calls.push_back(proc);
}
// Merge used tables
// QQ ...or just open tables in thd->open_tables?
// This is not entirerly clear at the moment, but for now, we collect
// tables here.
for (SELECT_LEX *sl= thd->lex.all_selects_list ;
sl ;
sl= sl->next_select())
{
for (TABLE_LIST *tables= sl->get_table_list() ;
tables ;
tables= tables->next)
{
List_iterator_fast<char *> li(m_tables);
char **tb;
while ((tb= li++))
if (strcasecmp(tables->real_name, *tb) == 0)
break;
if (! tb)
m_tables.push_back(&tables->real_name);
}
}
memcpy(&thd->lex, &m_lex, sizeof(LEX)); // Restore lex
}
void
sp_head::push_backpatch(sp_instr *i, sp_label_t *lab)
{
bp_t *bp= (bp_t *)my_malloc(sizeof(bp_t), MYF(MY_WME));
if (bp)
{
bp->lab= lab;
bp->instr= i;
(void)m_backpatch.push_front(bp);
}
}
void
sp_head::backpatch(sp_label_t *lab)
{
bp_t *bp;
uint dest= instructions();
List_iterator_fast<bp_t> li(m_backpatch);
while ((bp= li++))
if (bp->lab == lab)
{
sp_instr_jump *i= static_cast<sp_instr_jump *>(bp->instr);
i->set_destination(dest);
}
}
// ------------------------------------------------------------------
//
// sp_instr_stmt
//
int
sp_instr_stmt::execute(THD *thd, uint *nextp)
{
LEX olex; // The other lex
memcpy(&olex, &thd->lex, sizeof(LEX)); // Save the other lex
memcpy(&thd->lex, &m_lex, sizeof(LEX)); // Use my own lex
thd->lex.thd = thd;
mysql_execute_command(thd);
memcpy(&thd->lex, &olex, sizeof(LEX)); // Restore the other lex
*nextp = m_ip+1;
return 0;
}
//
// sp_instr_set
//
int
sp_instr_set::execute(THD *thd, uint *nextp)
{
thd->spcont->set_item(m_offset, eval_func_item(thd, m_value, m_type));
*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(thd, 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(thd, m_expr, MYSQL_TYPE_TINY);
if (! it->val_int())
*nextp = m_dest;
else
*nextp = m_ip+1;
return 0;
}
/* -*- 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>
struct sp_label;
class sp_instr;
class sp_head : public Sql_alloc
{
sp_head(const sp_head &); /* Prevent use of these */
void operator=(sp_head &);
public:
my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
List<Item_string> m_calls; // Called procedures.
List<char *> m_tables; // Used tables.
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);
// Put the instruction on the backpatch list, associated with the label.
void
push_backpatch(sp_instr *, struct sp_label *);
// Update all instruction with this label in the backpatch list to
// the current position.
void
backpatch(struct sp_label *);
private:
Item_string *m_name;
Item_string *m_defstr;
LEX *m_call_lex; // The CALL's own lex
LEX m_lex; // Temp. store for the other lex
DYNAMIC_ARRAY m_instr; // The "instructions"
typedef struct
{
struct sp_label *lab;
sp_instr *instr;
} bp_t;
List<bp_t> m_backpatch; // Instructions needing backpaching
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
//
// "Instructions"...
//
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(uint ip)
: Sql_alloc(), m_ip(ip)
{}
virtual ~sp_instr()
{}
// 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, uint *nextp)
{ // Default is a no-op.
*nextp = m_ip+1; // Next instruction
return 0;
}
protected:
uint m_ip; // My index
}; // 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(uint ip)
: sp_instr(ip)
{}
virtual ~sp_instr_stmt()
{}
virtual int execute(THD *thd, uint *nextp);
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 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, uint *nextp);
private:
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;
}
protected:
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:
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:
Item *m_expr; // The condition
}; // class sp_instr_jump_if_not : public sp_instr_jump
#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"
#include "sp_head.h"
sp_pcontext::sp_pcontext()
: 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
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;
}
}
sp_label_t *
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);
}
return lab;
}
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;
}
/* -*- 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;
typedef struct sp_label
{
char *name;
uint ip; // Instruction index
} sp_label_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);
// Pop the last 'num' slots of the frame
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;
}
sp_label_t *
push_label(char *name, uint ip);
sp_label_t *
find_label(char *name);
inline sp_label_t *
last_label()
{
return m_label.head();
}
inline sp_label_t *
pop_label()
{
return m_label.pop();
}
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();
List<sp_label_t> m_label; // The label list
uint m_genlab; // Gen. label counter
}; // 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 };
...@@ -524,6 +525,7 @@ class THD :public ilink { ...@@ -524,6 +525,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;
...@@ -172,6 +173,8 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) ...@@ -172,6 +173,8 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
lex->sql_command=SQLCOM_END; lex->sql_command=SQLCOM_END;
lex->safe_to_cache_query= 1; lex->safe_to_cache_query= 1;
lex->tmp_table_used= 0; lex->tmp_table_used= 0;
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
...@@ -404,6 +409,7 @@ typedef struct st_lex ...@@ -404,6 +409,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 */
...@@ -462,6 +468,8 @@ typedef struct st_lex ...@@ -462,6 +468,8 @@ typedef struct st_lex
CHARSET_INFO *charset; CHARSET_INFO *charset;
char *help_arg; char *help_arg;
bool tmp_table_used; bool tmp_table_used;
sp_head *sphead;
sp_pcontext *spcont;
} LEX; } LEX;
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
#include "ha_innodb.h" #include "ha_innodb.h"
#endif #endif
#include "sp_head.h"
#include "sp.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
...@@ -2808,6 +2811,84 @@ mysql_execute_command(THD *thd) ...@@ -2808,6 +2811,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>
...@@ -121,6 +123,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -121,6 +123,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
...@@ -200,6 +203,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -200,6 +203,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
...@@ -244,6 +248,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -244,6 +248,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
...@@ -258,6 +263,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -258,6 +263,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
...@@ -298,6 +304,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -298,6 +304,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
...@@ -336,6 +343,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -336,6 +343,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
...@@ -522,6 +530,21 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -522,6 +530,21 @@ 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
/* QQ This is temporary, until the REPEAT conflict is solved. */
%token SPREPEAT_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
%token ISSUER_SYM %token ISSUER_SYM
%token SUBJECT_SYM %token SUBJECT_SYM
%token CIPHER_SYM %token CIPHER_SYM
...@@ -671,8 +694,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -671,8 +694,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_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
...@@ -698,10 +725,16 @@ query: ...@@ -698,10 +725,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
...@@ -881,7 +914,414 @@ create: ...@@ -881,7 +914,414 @@ 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_stmt
{
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_stmts:
sp_proc_stmt ';'
| sp_proc_stmts sp_proc_stmt ';'
;
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;
}
;
sp_proc_stmt:
{
Lex->sphead->reset_lex(YYTHD);
}
statement
{
LEX *lex= Lex;
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);
}
| IF sp_if END IF {}
| CASE_SYM WHEN_SYM
{
Lex->sphead->m_simple_case= FALSE;
}
sp_case END CASE_SYM {}
| CASE_SYM expr WHEN_SYM
{
/* We "fake" this by using an anonymous variable which we
set to the expression. Note that all WHENs are evaluate
at the same frame level, so we then know that it's the
top-most variable in the frame. */
LEX *lex= Lex;
uint offset= lex->spcont->current_framesize();
sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
offset, $2, MYSQL_TYPE_STRING);
LEX_STRING dummy;
dummy.str= (char *)"";
dummy.length= 0;
lex->spcont->push(&dummy, MYSQL_TYPE_STRING, sp_param_in);
lex->sphead->add_instr(i);
lex->sphead->m_simple_case= TRUE;
}
sp_case END CASE_SYM
{
Lex->spcont->pop();
}
| sp_labeled_control
{}
| { /* Unlabeled controls get a secret label. */
LEX *lex= Lex;
lex->spcont->push_label((char *)"", lex->sphead->instructions());
}
sp_unlabeled_control
{
LEX *lex= Lex;
lex->sphead->backpatch(lex->spcont->pop_label());
}
| LEAVE_SYM IDENT
{
LEX *lex= Lex;
sp_head *sp = lex->sphead;
sp_label_t *lab= lex->spcont->find_label($2.str);
if (! lab)
{
printf("QQ LEAVE with no matching label\n");
YYABORT;
}
else
{
sp_instr_jump *i= new sp_instr_jump(sp->instructions());
sp->push_backpatch(i, lab); /* Jumping forward */
sp->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); /* Jump back */
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(lex->sphead->instructions(),
spv->offset, $4, spv->type);
lex->sphead->add_instr(i);
spv->isset= TRUE;
}
}
;
sp_if:
expr THEN_SYM
{
sp_head *sp= Lex->sphead;
sp_pcontext *ctx= Lex->spcont;
uint ip= sp->instructions();
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $1);
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
sp->add_instr(i);
}
sp_proc_stmts
{
sp_head *sp= Lex->sphead;
sp_pcontext *ctx= Lex->spcont;
uint ip= sp->instructions();
sp_instr_jump *i = new sp_instr_jump(ip);
sp->add_instr(i);
sp->backpatch(ctx->pop_label());
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
}
sp_elseifs
{
LEX *lex= Lex;
lex->sphead->backpatch(lex->spcont->pop_label());
}
;
sp_elseifs:
/* Empty */
| ELSEIF_SYM sp_if
| ELSE sp_proc_stmts
;
sp_case:
expr THEN_SYM
{
sp_head *sp= Lex->sphead;
sp_pcontext *ctx= Lex->spcont;
uint ip= sp->instructions();
sp_instr_jump_if_not *i;
if (! sp->m_simple_case)
i= new sp_instr_jump_if_not(ip, $1);
else
{ /* Simple case: <caseval> = <whenval> */
Item *var= (Item*) new Item_splocal(ctx->current_framesize()-1);
Item *expr= Item_bool_func2::eq_creator(var, $1);
i= new sp_instr_jump_if_not(ip, expr);
}
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
sp->add_instr(i);
}
sp_proc_stmts
{
sp_head *sp= Lex->sphead;
sp_pcontext *ctx= Lex->spcont;
uint ip= sp->instructions();
sp_instr_jump *i = new sp_instr_jump(ip);
sp->add_instr(i);
sp->backpatch(ctx->pop_label());
sp->push_backpatch(i, ctx->push_label((char *)"", 0));
}
sp_whens
{
LEX *lex= Lex;
lex->sphead->backpatch(lex->spcont->pop_label());
}
;
sp_whens:
/* Empty */
| WHEN_SYM sp_case
| ELSE sp_proc_stmts
;
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
{
lex->spcont->pop_label();
lex->sphead->backpatch(lab);
}
}
;
sp_unlabeled_control:
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
{
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
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
uint ip= sp->instructions();
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $2);
/* Jumping forward */
sp->push_backpatch(i, lex->spcont->last_label());
sp->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: create2:
'(' field_list ')' opt_create_table_options create3 {} '(' field_list ')' opt_create_table_options create3 {}
...@@ -1437,8 +1877,27 @@ alter: ...@@ -1437,8 +1877,27 @@ alter:
LEX *lex=Lex; LEX *lex=Lex;
lex->sql_command=SQLCOM_ALTER_DB; lex->sql_command=SQLCOM_ALTER_DB;
lex->name=$3.str; lex->name=$3.str;
}; }
| 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
...@@ -2969,7 +3428,16 @@ drop: ...@@ -2969,7 +3428,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:
...@@ -3022,7 +3490,6 @@ replace: ...@@ -3022,7 +3490,6 @@ replace:
} }
insert_field_spec insert_field_spec
{} {}
{}
; ;
insert_lock_option: insert_lock_option:
...@@ -3706,8 +4173,25 @@ order_ident: ...@@ -3706,8 +4173,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