Commit d956a1c5 authored by unknown's avatar unknown

Merged 4.1 -> 5.0.


BitKeeper/etc/logging_ok:
  auto-union
client/mysql.cc:
  Auto merged
configure.in:
  Auto merged
mysql-test/r/rpl_temporary.result:
  Auto merged
mysql-test/r/subselect.result:
  Auto merged
mysql-test/t/subselect.test:
  Auto merged
scripts/mysql_install_db.sh:
  Auto merged
sql/item.h:
  Auto merged
sql/item_func.h:
  Auto merged
sql/lex.h:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/sql_class.cc:
  Auto merged
sql/sql_class.h:
  Auto merged
sql/sql_lex.h:
  Auto merged
sql/sql_parse.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
parents 18d3292b 867efa28
......@@ -6,6 +6,7 @@ FROM=$USER@mysql.com
INTERNALS=internals@lists.mysql.com
DOCS=docs-commit@mysql.com
LIMIT=10000
REPOV=5.0
if [ "$REAL_EMAIL" = "" ]
then
......@@ -27,15 +28,15 @@ CHANGESET=`bk -R prs -r+ -h -d':I:' ChangeSet`
echo "Commit successful, notifying developers at $TO"
(
cat <<EOF
List-ID: <bk.mysql-4.1>
List-ID: <bk.mysql-$REPOV>
From: $FROM
To: $TO
Subject: bk commit - 4.1 tree ($CHANGESET)
Subject: bk commit - $REPOV tree ($CHANGESET)
EOF
bk changes -v -r+
bk cset -r+ -d
) | head -n $LIMIT | /usr/sbin/sendmail -t
) | /usr/sbin/sendmail -t
#++
# internals@ mail
......@@ -43,13 +44,13 @@ EOF
echo "Notifying internals list at $INTERNALS"
(
cat <<EOF
List-ID: <bk.mysql-4.1>
List-ID: <bk.mysql-$REPOV>
From: $FROM
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
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
push, to the public repository.
For information on how to access the public repository
......@@ -70,15 +71,15 @@ EOF
echo "Notifying docs list at $DOCS"
(
cat <<EOF
List-ID: <bk.mysql-4.1>
List-ID: <bk.mysql-$REPOV>
From: $FROM
To: $DOCS
Subject: bk commit - 4.1 tree (Manual) ($CHANGESET)
Subject: bk commit - $REPOV tree (Manual) ($CHANGESET)
EOF
bk changes -v -r+
bk cset -r+ -d
) | head -n $LIMIT | /usr/sbin/sendmail -t
) | /usr/sbin/sendmail -t
fi
else
......
This diff is collapsed.
Stored Procedures implemented 2003-03-07:
Summary of Not Yet Implemented:
- SQL queries (like SELECT, INSERT, UPDATE etc) in FUNCTION bodies
- External languages
- Access control
- Routine characteristics (mostly used for external languages)
- Prepared SP caching; SPs are fetched and reparsed at each call
- SQL-99 COMMIT (related to BEGIN/END)
- DECLARE CURSOR ...
- FOR-loops (as it requires cursors)
- CASCADE/RESTRICT for ALTER and DROP
- ALTER/DROP METHOD (as it implies User Defined Types)
- CONDITIONs, HANDLERs, SIGNAL and RESIGNAL (will probably not be implemented)
Summary of what's implemented:
- SQL PROCEDUREs/FUNCTIONs (CREATE/DROP)
- CALL
- DECLARE of local variables
- BEGIN/END, SET, CASE, IF, LOOP, WHILE, REPEAT, ITERATE, LEAVE
- SELECT INTO local variables
- "Non-query" FUNCTIONs only
List of what's implemented:
- CREATE PROCEDURE|FUNCTION name ( args ) body
No routine characteristics yet.
- ALTER PROCEDURE|FUNCTION name ...
Is parsed, but a no-op (as there are no characteristics implemented yet).
CASCADE/RESTRICT is not implemented (and CASCADE probably will not be).
- DROP PROCEDURE|FUNCTION name
CASCADE/RESTRICT is not implemented (and CASCADE probably will not be).
- CALL name (args)
OUT and INOUT parameters are only supported for local variables, and
therefore only useful when calling such procedures from within another
procedure.
Note: For the time being, when a procedure with OUT/INOUT parameter is
called, the out values are silently discarded. In the future, this
will either generate an error message, or it might even work to
call all procedures from the top-level.
- Function/Procedure body:
- BEGIN/END
Is parsed, but not the real thing with (optional) transaction
control, it only serves as block syntax for multiple statements (and
local variable binding).
Note: Multiple statements requires a client that can send bodies
containing ";". This is handled in the CLI clients mysql and
mysqltest with the "delimiter" command. Changing the end-of-query
delimiter ";" to for instance "|" allows ";" to be used in the
routine body.
- SET of local variables
Implemented as part of the pre-existing SET syntax. This allows an
extended syntax of "SET a=x, b=y, ..." where different variable types
(SP local and global) can be mixed. This also allows combinations
of local variables and some options that only make sense for
global/system variables; in that case the options are accepted but
ignored.
- The flow control constructs: CASE, IF, LOOP, WHILE, ITERATE and LEAVE
are fully implemented.
- SELECT ... INTO local variables (as well as global session variables)
is implemented. (Note: This is not SQL-99 feature, but common in other
databases.)
- A FUNCTION can have flow control contructs, but must not contain
an SQL query, like SELECT, INSERT, UPDATE, etc. The reason is that it's
hard to allow this is that a FUNCTION is executed as part of another
query (unlike a PROCEDURE, which is called as a statement). The table
locking scheme used makes it difficult to allow "subqueries" during
FUNCTION invokation.
Closed questions:
- What is the expected result when creating a procedure with a name that
already exists? An error or overwrite?
Answer: Error
- Do PROCEDUREs and FUNCTIONs share namespace or not? I think not, but the
we need to flag the type in the mysql.proc table and the name alone is
not a unique key any more, or, we have separate tables.
(Unfortunately, mysql.func is already taken. Use "sfunc" and maybe even
rename "proc" into "sproc" while we still can, for consistency?)
Answer: Same tables, with an additional key-field for the type.
Open questions/issues:
- SQL-99 variables and parameters are typed. For the present we don't do
any type checking, since this is the way MySQL works. I still don't know
if we should keep it this way, or implement type checking. Possibly we
should have optional, uset-settable, type checking.
......@@ -104,6 +104,7 @@ extern "C" {
#include "completion_hash.h"
#define PROMPT_CHAR '\\'
#define DEFAULT_DELIMITER ';'
typedef struct st_status
{
......@@ -156,6 +157,7 @@ static char pager[FN_REFLEN], outfile[FN_REFLEN];
static FILE *PAGER, *OUTFILE;
static MEM_ROOT hash_mem_root;
static uint prompt_counter;
static char delimiter= DEFAULT_DELIMITER;
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
......@@ -183,7 +185,7 @@ static int com_quit(String *str,char*),
com_use(String *str,char*), com_source(String *str, char*),
com_rehash(String *str, char*), com_tee(String *str, char*),
com_notee(String *str, char*),
com_prompt(String *str, char*);
com_prompt(String *str, char*), com_delimiter(String *str, char*);
#ifdef USE_POPEN
static int com_nopager(String *str, char*), com_pager(String *str, char*),
......@@ -251,7 +253,8 @@ static COMMANDS commands[] = {
"Set outfile [to_outfile]. Append everything into given outfile." },
{ "use", 'u', com_use, 1,
"Use another database. Takes database name as argument." },
{ "delimiter", 'd', com_delimiter, 1,
"Set query delimiter. " },
/* Get bash-like expansion for some commands */
{ "create table", 0, 0, 0, ""},
{ "create database", 0, 0, 0, ""},
......@@ -920,7 +923,7 @@ static COMMANDS *find_command (char *name,char cmd_char)
{
while (my_isspace(charset_info,*name))
name++;
if (strchr(name,';') || strstr(name,"\\g"))
if (strchr(name, delimiter) || strstr(name,"\\g"))
return ((COMMANDS *) 0);
if ((end=strcont(name," \t")))
{
......@@ -998,7 +1001,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
return 1; // Quit
if (com->takes_params)
{
for (pos++ ; *pos && *pos != ';' ; pos++) ; // Remove parameters
for (pos++ ; *pos && *pos != delimiter; pos++) ; // Remove parameters
if (!*pos)
pos--;
}
......@@ -1014,7 +1017,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
continue;
}
}
else if (!*ml_comment && inchar == ';' && !*in_string)
else if (!*ml_comment && inchar == delimiter && !*in_string)
{ // ';' is end of command
if (out != line)
buffer.append(line,(uint) (out-line)); // Add this line
......@@ -1531,7 +1534,7 @@ com_help(String *buffer __attribute__((unused)),
for (i = 0; commands[i].name; i++)
{
if (commands[i].func)
tee_fprintf(stdout, "%s\t(\\%c)\t%s\n", commands[i].name,
tee_fprintf(stdout, "%-10s(\\%c)\t%s\n", commands[i].name,
commands[i].cmd_char, commands[i].doc);
}
}
......@@ -2368,6 +2371,37 @@ static int com_source(String *buffer, char *line)
return error;
}
/* ARGSUSED */
static int
com_delimiter(String *buffer __attribute__((unused)), char *line)
{
char *tmp;
char buff[256];
if (strlen(line)> 255)
{
put_info("'DELIMITER' command was too long.", INFO_ERROR);
return 0;
}
bzero(buff, sizeof(buff));
strmov(buff, line);
tmp= get_arg(buff, 0);
if (!tmp || !*tmp)
{
put_info("DELIMITER must be followed by a 'delimiter' char", INFO_ERROR);
return 0;
}
if (strlen(tmp)> 1)
{
put_info("Argument must be one char", INFO_ERROR);
return 0;
}
delimiter= *tmp;
return 0;
}
/* ARGSUSED */
static int
......
......@@ -89,6 +89,7 @@
#define SLAVE_POLL_INTERVAL 300000 /* 0.3 of a sec */
#define DEFAULT_DELIMITER ';'
enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD,
OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC};
......@@ -124,6 +125,8 @@ static int block_ok_stack[BLOCK_STACK_DEPTH];
static uint global_expected_errno[MAX_EXPECTED_ERRORS], global_expected_errors;
static CHARSET_INFO *charset_info= &my_charset_latin1;
static char delimiter= DEFAULT_DELIMITER;
DYNAMIC_ARRAY q_lines;
typedef struct
......@@ -198,7 +201,7 @@ Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER,
Q_WAIT_FOR_SLAVE_TO_STOP,
Q_REQUIRE_VERSION,
Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS,
Q_ENABLE_INFO, Q_DISABLE_INFO,
Q_ENABLE_INFO, Q_DISABLE_INFO, Q_DELIMITER,
Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */
Q_COMMENT_WITH_COMMAND
......@@ -261,6 +264,7 @@ const char *command_names[]=
"disable_warnings",
"enable_info",
"disable_info",
"delimiter",
0
};
......@@ -1530,6 +1534,16 @@ int do_while(struct st_query* q)
return 0;
}
int do_delimiter(char *p)
{
while (*p && my_isspace(system_charset_info,*p))
p++;
if (!*p)
die("Missing delimiter character\n");
delimiter=*p;
return 0;
}
int safe_copy_unescape(char* dest, char* src, int size)
{
......@@ -1609,7 +1623,7 @@ int read_line(char* buf, int size)
switch(state) {
case R_NORMAL:
/* Only accept '{' in the beginning of a line */
if (c == ';')
if (c == delimiter)
{
*p = 0;
return 0;
......@@ -1649,7 +1663,7 @@ int read_line(char* buf, int size)
*buf = 0;
return 0;
}
else if (c == ';' || c == '{')
else if (c == delimiter || c == '{')
{
*p = 0;
return 0;
......@@ -1669,7 +1683,7 @@ int read_line(char* buf, int size)
state = R_ESC_SLASH_Q1;
break;
case R_ESC_Q_Q1:
if (c == ';')
if (c == delimiter)
{
*p = 0;
return 0;
......@@ -1690,7 +1704,7 @@ int read_line(char* buf, int size)
state = R_ESC_SLASH_Q2;
break;
case R_ESC_Q_Q2:
if (c == ';')
if (c == delimiter)
{
*p = 0;
return 0;
......@@ -2536,6 +2550,9 @@ int main(int argc, char** argv)
do_sync_with_master2("");
break;
}
case Q_DELIMITER:
do_delimiter(q->first_argument);
break;
case Q_COMMENT: /* Ignore row */
case Q_COMMENT_WITH_COMMAND:
case Q_PING:
......
......@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM
# 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)
PROTOCOL_VERSION=10
......
......@@ -270,4 +270,16 @@
#define ER_COLLATION_CHARSET_MISMATCH 1251
#define ER_SLAVE_WAS_RUNNING 1252
#define ER_SLAVE_WAS_NOT_RUNNING 1253
#define ER_ERROR_MESSAGES 254
#define ER_SP_NO_RECURSIVE_CREATE 1254
#define ER_SP_ALREADY_EXISTS 1255
#define ER_SP_DOES_NOT_EXIST 1256
#define ER_SP_DROP_FAILED 1257
#define ER_SP_STORE_FAILED 1258
#define ER_SP_LILABEL_MISMATCH 1259
#define ER_SP_LABEL_REDEFINE 1260
#define ER_SP_LABEL_MISMATCH 1261
#define ER_SP_UNINIT_VAR 1262
#define ER_SP_BADSELECT 1263
#define ER_SP_BADRETURN 1264
#define ER_SP_BADQUERY 1265
#define ER_ERROR_MESSAGES 266
......@@ -55,7 +55,8 @@ sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \
sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc time.cc \
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \
spatial.cc gstream.cc sql_help.cc
spatial.cc gstream.cc sql_help.cc \
sp_head.cc sp_pcontext.cc sp.cc
EXTRA_DIST = lib_vio.c
......
......@@ -69,6 +69,7 @@ c_t="" c_c=""
c_hl="" c_hl=""
c_hc="" c_hc=""
c_clr="" c_clr=""
c_p=""
# Check for old tables
if test ! -f $mdata/db.frm
......@@ -246,6 +247,17 @@ then
c_hc="$c_hc comment='categories of help topics';"
fi
if test ! -f $mdata/proc.frm
then
c_p="$c_p CREATE TABLE proc ("
c_p="$c_p name char(64) binary DEFAULT '' NOT NULL,"
c_p="$c_p type enum('function','procedure') NOT NULL,"
c_p="$c_p body blob DEFAULT '' NOT NULL,"
c_p="$c_p PRIMARY KEY (name,type)"
c_p="$c_p )"
c_p="$c_p comment='Stored Procedures';"
fi
mysqld_boot=" $execdir/mysqld --no-defaults --bootstrap --skip-grant-tables \
--basedir=$basedir --datadir=$ldata --skip-innodb --skip-bdb $EXTRA_ARG"
echo "running $mysqld_boot"
......@@ -270,6 +282,9 @@ $c_c
$c_hl
$c_hc
$c_clr
$c_p
END_OF_DATA
then
exit 0
......
......@@ -7,6 +7,7 @@ help_category
help_relation
help_topic
host
proc
tables_priv
user
show tables;
......@@ -22,6 +23,7 @@ help_category
help_relation
help_topic
host
proc
tables_priv
user
show tables;
......@@ -37,6 +39,7 @@ help_category
help_relation
help_topic
host
proc
tables_priv
user
show tables;
......
......@@ -64,3 +64,16 @@ use test_$1;
create table t1 (c int);
insert into test_$1.t1 set test_$1.t1.c = '1';
drop database test_$1;
use test;
drop table if exists t1,t2,t3;
create table t1(id1 int not null auto_increment primary key, t char(12));
create table t2(id2 int not null, t char(12));
create table t3(id3 int not null, t char(12), index(id3));
select count(*) from t2;
count(*)
500
insert into t2 select t1.* from t1, t2 t, t3 where t1.id1 = t.id2 and t.id2 = t3.id3;
select count(*) from t2;
count(*)
25500
drop table if exists t1,t2,t3;
......@@ -127,6 +127,7 @@ insert into t1 values (1);
show open tables;
Database Table In_use Name_locked
test t1 0 0
mysql proc 0 0
drop table t1;
create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CHECKSUM=1 COMMENT="test" TYPE=MYISAM MIN_ROWS=10 MAX_ROWS=100 PACK_KEYS=1 DELAY_KEY_WRITE=1 ROW_FORMAT=fixed;
show create table t1;
......
delete from mysql.proc;
create procedure proc1()
set @x = 42;
create function func1() returns int
return 42;
create procedure foo()
create procedure bar() set @x=3;
Can't create a PROCEDURE from within another stored routine
create procedure foo()
create function bar() returns double return 2.3;
Can't create a FUNCTION from within another stored routine
create procedure proc1()
set @x = 42;
PROCEDURE proc1 already exists
create function func1() returns int
return 42;
FUNCTION func1 already exists
alter procedure foo;
PROCEDURE foo does not exist
alter function foo;
FUNCTION foo does not exist
drop procedure foo;
PROCEDURE foo does not exist
drop function foo;
FUNCTION foo does not exist
call foo();
PROCEDURE foo does not exist
create procedure foo()
foo: loop
leave bar;
end loop;
LEAVE with no matching label: bar
create procedure foo()
foo: loop
iterate bar;
end loop;
ITERATE with no matching label: bar
create procedure foo()
foo: loop
foo: loop
set @x=2;
end loop foo;
end loop foo;
Redefining label foo
create procedure foo()
foo: loop
set @x=2;
end loop bar;
End-label bar without match
create procedure foo(out x int)
begin
declare y int;
set x = y;
end;
Referring to uninitialized variable y
create procedure foo(x int)
select * from test.t1;
SELECT in a stored procedure must have INTO
create procedure foo()
return 42;
RETURN is only allowed in a FUNCTION
create function foo() returns int
begin
declare x int;
select max(c) into x from test.t;
return x;
end;
Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION
drop procedure proc1;
drop function func1;
This diff is collapsed.
......@@ -14,6 +14,6 @@ update t1 set n = 3;
unlock tables;
show status like 'Table_lock%';
Variable_name Value
Table_locks_immediate 3
Table_locks_immediate 4
Table_locks_waited 1
drop table t1;
......@@ -593,7 +593,6 @@ x
3
3
INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
You can't specify target table 't1' for update in FROM clause
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2));
select * from t1;
x
......@@ -601,6 +600,8 @@ x
2
3
3
11
11
0
drop table t1, t2, t3;
CREATE TABLE t1 (x int not null, y int, primary key (x));
......
......@@ -65,3 +65,34 @@ use test_$1;
create table t1 (c int);
insert into test_$1.t1 set test_$1.t1.c = '1';
drop database test_$1;
use test;
--disable_warnings
drop table if exists t1,t2,t3;
--enable_warnings
create table t1(id1 int not null auto_increment primary key, t char(12));
create table t2(id2 int not null, t char(12));
create table t3(id3 int not null, t char(12), index(id3));
disable_query_log;
let $1 = 100;
while ($1)
{
let $2 = 5;
eval insert into t1(t) values ('$1');
while ($2)
{
eval insert into t2(id2,t) values ($1,'$2');
let $3 = 10;
while ($3)
{
eval insert into t3(id3,t) values ($1,'$2');
dec $3;
}
dec $2;
}
dec $1;
}
enable_query_log;
select count(*) from t2;
insert into t2 select t1.* from t1, t2 t, t3 where t1.id1 = t.id2 and t.id2 = t3.id3;
select count(*) from t2;
drop table if exists t1,t2,t3;
#
# Stored PROCEDURE error tests
#
# Make sure we don't have any procedures left.
delete from mysql.proc;
delimiter |;
# Check that we get the right error, i.e. UDF declaration parses correctly,
# but foo.so doesn't exist.
# QQ This generates an error message containing a misleading errno which
# might vary between systems (it usually doesn't have anything to do with
# the actual failing dlopen()).
#--error 1126
#create function foo returns real soname "foo.so"|
create procedure proc1()
set @x = 42|
create function func1() returns int
return 42|
# Can't create recursively
--error 1250
create procedure foo()
create procedure bar() set @x=3|
--error 1250
create procedure foo()
create function bar() returns double return 2.3|
# Already exists
--error 1251
create procedure proc1()
set @x = 42|
--error 1251
create function func1() returns int
return 42|
# Does not exist
--error 1252
alter procedure foo|
--error 1252
alter function foo|
--error 1252
drop procedure foo|
--error 1252
drop function foo|
--error 1252
call foo()|
# LEAVE/ITERATE with no match
--error 1255
create procedure foo()
foo: loop
leave bar;
end loop|
--error 1255
create procedure foo()
foo: loop
iterate bar;
end loop|
# Redefining label
--error 1256
create procedure foo()
foo: loop
foo: loop
set @x=2;
end loop foo;
end loop foo|
# End label mismatch
--error 1257
create procedure foo()
foo: loop
set @x=2;
end loop bar|
# Referring to undef variable
--error 1258
create procedure foo(out x int)
begin
declare y int;
set x = y;
end|
# We require INTO in SELECTs (for now; this might change in the future)
--error 1259
create procedure foo(x int)
select * from test.t1|
# RETURN in FUNCTION only
--error 1260
create procedure foo()
return 42|
# Doesn't allow queries in FUNCTIONs (for now :-( )
--error 1261
create function foo() returns int
begin
declare x int;
select max(c) into x from test.t;
return x;
end|
drop procedure proc1|
drop function func1|
delimiter ;|
This diff is collapsed.
......@@ -343,7 +343,6 @@ INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(a) FROM t2));
select * from t1;
INSERT INTO t1 (x) select (SELECT SUM(a)+1 FROM t2) FROM t2;
select * from t1;
-- error 1093
INSERT INTO t1 (x) select (SELECT SUM(x)+2 FROM t1) FROM t2;
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2));
-- sleep 1
......
......@@ -318,6 +318,19 @@ then
c_c="$c_c comment='Column privileges';"
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 type enum('function','procedure') NOT NULL,"
c_p="$c_p body blob DEFAULT '' NOT NULL,"
c_p="$c_p PRIMARY KEY (name,type)"
c_p="$c_p )"
c_p="$c_p comment='Stored Procedures';"
fi
echo "Installing all prepared tables"
if (
cat << END_OF_DATA
......@@ -336,6 +349,7 @@ $i_f
$c_t
$c_c
$c_p
END_OF_DATA
cat fill_help_tables.sql
) | 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 \
lex.h lex_symbol.h sql_acl.h sql_crypt.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
spatial.h gstream.h sp_head.h sp_pcontext.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 \
......@@ -85,7 +86,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
slave.cc sql_repl.cc sql_union.cc sql_derived.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
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_LDADD = $(LDADD) $(CXXLDFLAGS)
......
......@@ -22,6 +22,7 @@
#include "mysql_priv.h"
#include <m_ctype.h>
#include "my_dir.h"
#include "sp_rcontext.h"
/*****************************************************************************
** Item functions
......@@ -170,8 +171,25 @@ bool Item::get_time(TIME *ltime)
CHARSET_INFO * Item::default_charset() const
{
return current_thd->db_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)
{
set_field(f);
......
......@@ -114,6 +114,8 @@ class Item {
CHARSET_INFO *charset() const { return str_value.charset(); };
void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); }
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
virtual uint cols() { return 1; }
......@@ -127,6 +129,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 Item_ident :public Item
{
......
......@@ -30,6 +30,9 @@
#ifdef HAVE_COMPRESS
#include <zlib.h>
#endif
#include "sp_head.h"
#include "sp_rcontext.h"
#include "sp.h"
/* return TRUE if item is a constant */
......@@ -2818,3 +2821,75 @@ double Item_func_glength::val()
geom.length(&res));
return res;
}
int
Item_func_sp::execute(Item **itp)
{
DBUG_ENTER("Item_func_sp::execute");
THD *thd= current_thd;
if (! m_sp)
m_sp= sp_find_function(thd, &m_name);
if (! m_sp)
DBUG_RETURN(-1);
DBUG_RETURN(m_sp->execute_function(thd, args, arg_count, itp));
}
enum enum_field_types
Item_func_sp::field_type() const
{
DBUG_ENTER("Item_func_sp::field_type");
if (! m_sp)
m_sp= sp_find_function(current_thd, const_cast<LEX_STRING*>(&m_name));
if (m_sp)
{
DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns));
DBUG_RETURN(m_sp->m_returns);
}
DBUG_RETURN(MYSQL_TYPE_STRING);
}
Item_result
Item_func_sp::result_type() const
{
DBUG_ENTER("Item_func_sp::result_type");
DBUG_PRINT("info", ("m_sp = %p", m_sp));
if (! m_sp)
m_sp= sp_find_function(current_thd, const_cast<LEX_STRING*>(&m_name));
if (m_sp)
{
DBUG_RETURN(m_sp->result());
}
DBUG_RETURN(STRING_RESULT);
}
void
Item_func_sp::fix_length_and_dec()
{
DBUG_ENTER("Item_func_sp::fix_length_and_dec");
if (! m_sp)
m_sp= sp_find_function(current_thd, &m_name);
if (m_sp)
{
switch (m_sp->result()) {
case STRING_RESULT:
maybe_null= 1;
max_length= 0;
break;
case REAL_RESULT:
decimals= NOT_FIXED_DEC;
max_length= float_length(decimals);
break;
case INT_RESULT:
decimals= 0;
max_length= 21;
break;
}
}
DBUG_VOID_RETURN;
}
......@@ -1158,3 +1158,69 @@ enum Item_cast
ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR
};
/*
*
* Stored FUNCTIONs
*
*/
class sp_head;
class Item_func_sp :public Item_func
{
private:
LEX_STRING m_name;
mutable sp_head *m_sp;
int execute(Item **itp);
public:
Item_func_sp(LEX_STRING name)
:Item_func(), m_name(name), m_sp(NULL)
{}
Item_func_sp(LEX_STRING name, List<Item> &list)
:Item_func(list), m_name(name), m_sp(NULL)
{}
virtual ~Item_func_sp()
{}
const char *func_name() const
{
return m_name.str;
}
enum enum_field_types field_type() const;
Item_result result_type() const;
longlong val_int()
{
return (longlong)Item_func_sp::val();
}
double val()
{
Item *it;
if (execute(&it))
return 0.0;
return it->val();
}
String *val_str(String *str)
{
Item *it;
if (execute(&it))
return NULL;
return it->val_str(str);
}
void fix_length_and_dec();
};
......@@ -60,6 +60,7 @@ static SYMBOL symbols[] = {
{ "AS", SYM(AS),0,0},
{ "ASC", SYM(ASC),0,0},
{ "ASCII", SYM(ASCII_SYM),0,0},
{ "ASENSITIVE", SYM(ASENSITIVE_SYM),0,0},
{ "AVG", SYM(AVG_SYM),0,0},
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0},
{ "AUTO_INCREMENT", SYM(AUTO_INC),0,0},
......@@ -81,6 +82,7 @@ static SYMBOL symbols[] = {
{ "BY", SYM(BY),0,0},
{ "BYTE", SYM(BYTE_SYM), 0, 0},
{ "CACHE", SYM(CACHE_SYM),0,0},
{ "CALL", SYM(CALL_SYM),0,0},
{ "CASCADE", SYM(CASCADE),0,0},
{ "CASE", SYM(CASE_SYM),0,0},
{ "CHAR", SYM(CHAR_SYM),0,0},
......@@ -109,6 +111,7 @@ static SYMBOL symbols[] = {
{ "CURRENT_DATE", SYM(CURDATE),0,0},
{ "CURRENT_TIME", SYM(CURTIME),0,0},
{ "CURRENT_TIMESTAMP", SYM(NOW_SYM),0,0},
{ "CURSOR", SYM(CURSOR_SYM),0,0},
{ "DATA", SYM(DATA_SYM),0,0},
{ "DATABASE", SYM(DATABASE),0,0},
{ "DATABASES", SYM(DATABASES),0,0},
......@@ -120,6 +123,7 @@ static SYMBOL symbols[] = {
{ "DAY_SECOND", SYM(DAY_SECOND_SYM),0,0},
{ "DEC", 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},
{ "DEFAULT", SYM(DEFAULT),0,0},
{ "DELAYED", SYM(DELAYED_SYM),0,0},
......@@ -142,6 +146,7 @@ static SYMBOL symbols[] = {
{ "ERRORS", SYM(ERRORS),0,0},
{ "END", SYM(END),0,0},
{ "ELSE", SYM(ELSE),0,0},
{ "ELSEIF", SYM(ELSEIF_SYM),0,0},
{ "ESCAPE", SYM(ESCAPE_SYM),0,0},
{ "ESCAPED", SYM(ESCAPED),0,0},
{ "ENABLE", SYM(ENABLE_SYM),0,0},
......@@ -172,7 +177,7 @@ static SYMBOL symbols[] = {
{ "FOR", SYM(FOR_SYM),0,0},
{ "FULL", SYM(FULL),0,0},
{ "FULLTEXT", SYM(FULLTEXT_SYM),0,0},
{ "FUNCTION", SYM(UDF_SYM),0,0},
{ "FUNCTION", SYM(FUNCTION_SYM),0,0},
{ "GEOMETRY", SYM(GEOMETRY_SYM),0,0},
{ "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION),0,0},
{ "GLOBAL", SYM(GLOBAL_SYM),0,0},
......@@ -198,6 +203,8 @@ static SYMBOL symbols[] = {
{ "INNER", SYM(INNER_SYM),0,0},
{ "INNOBASE", SYM(INNOBASE_SYM),0,0},
{ "INNODB", SYM(INNOBASE_SYM),0,0},
{ "INOUT", SYM(INOUT_SYM),0,0},
{ "INSENSITIVE", SYM(INSENSITIVE_SYM),0,0},
{ "INSERT", SYM(INSERT),0,0},
{ "INSERT_METHOD", SYM(INSERT_METHOD),0,0},
{ "INT", SYM(INT_SYM),0,0},
......@@ -215,12 +222,14 @@ static SYMBOL symbols[] = {
{ "ISOLATION", SYM(ISOLATION),0,0},
{ "ISAM", SYM(ISAM_SYM),0,0},
{ "ISSUER", SYM(ISSUER_SYM),0,0},
{ "ITERATE", SYM(ITERATE_SYM),0,0},
{ "JOIN", SYM(JOIN_SYM),0,0},
{ "KEY", SYM(KEY_SYM),0,0},
{ "KEYS", SYM(KEYS),0,0},
{ "KILL", SYM(KILL_SYM),0,0},
{ "LAST", SYM(LAST_SYM),0,0},
{ "LEADING", SYM(LEADING),0,0},
{ "LEAVE", SYM(LEAVE_SYM),0,0},
{ "LEFT", SYM(LEFT),0,0},
{ "LEVEL", SYM(LEVEL_SYM),0,0},
{ "LIKE", SYM(LIKE),0,0},
......@@ -236,6 +245,7 @@ static SYMBOL symbols[] = {
{ "LOGS", SYM(LOGS_SYM),0,0},
{ "LONG", SYM(LONG_SYM),0,0},
{ "LONGBLOB", SYM(LONGBLOB),0,0},
{ "LOOP", SYM(LOOP_SYM),0,0},
{ "LONGTEXT", SYM(LONGTEXT),0,0},
{ "LOW_PRIORITY", SYM(LOW_PRIORITY),0,0},
{ "MASTER", SYM(MASTER_SYM),0,0},
......@@ -289,6 +299,7 @@ static SYMBOL symbols[] = {
{ "OPTIONALLY", SYM(OPTIONALLY),0,0},
{ "OR", SYM(OR),0,0},
{ "ORDER", SYM(ORDER_SYM),0,0},
{ "OUT", SYM(OUT_SYM),0,0},
{ "OUTER", SYM(OUTER),0,0},
{ "OUTFILE", SYM(OUTFILE),0,0},
{ "PACK_KEYS", SYM(PACK_KEYS_SYM),0,0},
......@@ -318,13 +329,15 @@ static SYMBOL symbols[] = {
{ "REPAIR", SYM(REPAIR),0,0},
{ "REPLACE", SYM(REPLACE),0,0},
{ "REPLICATION", SYM(REPLICATION),0,0},
{ "REPEAT", SYM(REPEAT_SYM),0,0},
{ "REPEATABLE", SYM(REPEATABLE_SYM),0,0},
{ "REQUIRE", SYM(REQUIRE_SYM),0,0},
{ "RESET", SYM(RESET_SYM),0,0},
{ "USER_RESOURCES", SYM(RESOURCES),0,0},
{ "RESTORE", SYM(RESTORE_SYM),0,0},
{ "RESTRICT", SYM(RESTRICT),0,0},
{ "RETURNS", SYM(UDF_RETURNS_SYM),0,0},
{ "RETURN", SYM(RETURN_SYM),0,0},
{ "RETURNS", SYM(RETURNS_SYM),0,0},
{ "REVOKE", SYM(REVOKE),0,0},
{ "RIGHT", SYM(RIGHT),0,0},
{ "RLIKE", SYM(REGEXP),0,0}, /* Like in mSQL2 */
......@@ -335,6 +348,7 @@ static SYMBOL symbols[] = {
{ "RTREE", SYM(RTREE_SYM),0,0},
{ "SECOND", SYM(SECOND_SYM),0,0},
{ "SELECT", SYM(SELECT_SYM),0,0},
{ "SENSITIVE", SYM(SENSITIVE_SYM),0,0},
{ "SERIAL", SYM(SERIAL_SYM),0,0},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
{ "SESSION", SYM(SESSION_SYM),0,0},
......@@ -349,6 +363,7 @@ static SYMBOL symbols[] = {
{ "SOME", SYM(ANY_SYM),0,0},
{ "SONAME", SYM(UDF_SONAME_SYM),0,0},
{ "SPATIAL", SYM(SPATIAL_SYM),0,0},
{ "SPECIFIC", SYM(SPECIFIC_SYM),0,0},
{ "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},
......@@ -391,6 +406,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},
......@@ -409,6 +425,7 @@ static SYMBOL symbols[] = {
{ "WRITE", SYM(WRITE_SYM),0,0},
{ "WHEN", SYM(WHEN_SYM),0,0},
{ "WHERE", SYM(WHERE),0,0},
{ "WHILE", SYM(WHILE_SYM),0,0},
{ "XOR", SYM(XOR),0,0},
{ "X509", SYM(X509_SYM),0,0},
{ "YEAR", SYM(YEAR_SYM),0,0},
......@@ -563,7 +580,6 @@ static SYMBOL sql_functions[] = {
{ "RADIANS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_radians)},
{ "RAND", SYM(RAND),0,0},
{ "RELEASE_LOCK", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_release_lock)},
{ "REPEAT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_repeat)},
{ "REVERSE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_reverse)},
{ "ROUND", SYM(ROUND),0,0},
{ "RPAD", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_rpad)},
......
......@@ -360,7 +360,7 @@ extern "C" pthread_handler_decl(handle_one_connection,arg);
extern "C" pthread_handler_decl(handle_bootstrap,arg);
void end_thread(THD *thd,bool put_in_cache);
void flush_thread_cache();
void mysql_execute_command(THD *thd);
int mysql_execute_command(THD *thd);
bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
......
......@@ -264,3 +264,15 @@ v/*
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -258,3 +258,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -266,3 +266,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -255,3 +255,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -260,3 +260,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -255,3 +255,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -259,9 +259,22 @@
"Referenz '%-.64s' wird nicht unterstützt (%s)",
"Für jede abgeleitete Tabelle muss ein eigener Alias angegeben werden.",
"Select %u wurde während der Optimierung reduziert.",
"Tabelle '%-.64s', die in einem der SELECT-Befehle verwendet wurde kann nicht in %-.32s verwendet werden",
"Tabelle '%-.64s', die in einem der SELECT-Befehle verwendet wurde kann nicht in %-.32s verwendet werden."
"Client does not support authentication protocol requested by server. Consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL"
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -255,3 +255,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -257,3 +257,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -255,3 +255,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -257,3 +257,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -255,3 +255,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -257,3 +257,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -257,3 +257,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -259,3 +259,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -255,3 +255,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -259,3 +259,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -258,3 +258,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -251,3 +251,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -263,3 +263,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -256,3 +256,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -255,3 +255,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
......@@ -260,3 +260,15 @@
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
"The slave was already running"
"The slave was already stopped"
"Can't create a %s from within another stored routine"
"%s %s already exists"
"%s %s does not exist"
"Failed to DROP %s %s"
"Failed to CREATE %s %s"
"%s with no matching label: %s"
"Redefining label %s"
"End-label %s without match"
"Referring to uninitialized variable %s"
"SELECT in a stored procedure must have INTO"
"RETURN is only allowed in a FUNCTION"
"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
/* 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"
static sp_head *
sp_find_cached_function(THD *thd, char *name, uint namelen);
/*
*
* DB storage of Stored PROCEDUREs and FUNCTIONs
*
*/
// *openeed=true means we opened ourselves
static int
db_find_routine_aux(THD *thd, int type, char *name, uint namelen,
enum thr_lock_type ltype, TABLE **tablep, bool *opened)
{
DBUG_ENTER("db_find_routine_aux");
DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name));
TABLE *table;
byte key[65]; // We know name is 64 and the enum is 1 byte
uint keylen;
int ret;
// Put the key together
keylen= namelen;
if (keylen > sizeof(key)-1)
keylen= sizeof(key)-1;
memcpy(key, name, keylen);
memset(key+keylen, (int)' ', sizeof(key)-1 - keylen); // Pad with space
key[sizeof(key)-1]= type;
keylen= sizeof(key);
for (table= thd->open_tables ; table ; table= table->next)
if (strcmp(table->table_cache_key, "mysql") == 0 &&
strcmp(table->real_name, "proc") == 0)
break;
if (table)
*opened= FALSE;
else
{
TABLE_LIST tables;
memset(&tables, 0, sizeof(tables));
tables.db= (char*)"mysql";
tables.real_name= tables.alias= (char*)"proc";
if (! (table= open_ltable(thd, &tables, ltype)))
{
*tablep= NULL;
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
}
*opened= TRUE;
}
if (table->file->index_read_idx(table->record[0], 0,
key, keylen,
HA_READ_KEY_EXACT))
{
*tablep= NULL;
DBUG_RETURN(SP_KEY_NOT_FOUND);
}
*tablep= table;
DBUG_RETURN(SP_OK);
}
static int
db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
{
DBUG_ENTER("db_find_routine");
DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name));
extern int yyparse(void *thd);
LEX *tmplex;
TABLE *table;
const char *defstr;
int ret;
bool opened;
// QQ Set up our own mem_root here???
ret= db_find_routine_aux(thd, type, name, namelen, TL_READ, &table, &opened);
if (ret != SP_OK)
goto done;
if ((defstr= get_field(&thd->mem_root, table->field[2])) == NULL)
{
ret= SP_GET_FIELD_FAILED;
goto done;
}
if (opened)
{
close_thread_tables(thd);
table= NULL;
}
tmplex= lex_start(thd, (uchar*)defstr, strlen(defstr));
if (yyparse(thd) || thd->is_fatal_error || tmplex->sphead == NULL)
ret= SP_PARSE_ERROR;
else
*sphp= tmplex->sphead;
done:
if (table && opened)
close_thread_tables(thd);
DBUG_RETURN(ret);
}
static int
db_create_routine(THD *thd, int type,
char *name, uint namelen, char *def, uint deflen)
{
DBUG_ENTER("db_create_routine");
DBUG_PRINT("enter", ("type: %d name: %*s def: %*s", type, namelen, name, deflen, def));
int ret;
TABLE *table;
TABLE_LIST tables;
memset(&tables, 0, sizeof(tables));
tables.db= (char*)"mysql";
tables.real_name= tables.alias= (char*)"proc";
if (! (table= open_ltable(thd, &tables, TL_WRITE)))
ret= SP_OPEN_TABLE_FAILED;
else
{
restore_record(table, 2); // Get default values for fields
table->field[0]->store(name, namelen, system_charset_info);
table->field[1]->store((longlong)type);
table->field[2]->store(def, deflen, system_charset_info);
if (table->file->write_row(table->record[0]))
ret= SP_WRITE_ROW_FAILED;
else
ret= SP_OK;
}
close_thread_tables(thd);
DBUG_RETURN(ret);
}
static int
db_drop_routine(THD *thd, int type, char *name, uint namelen)
{
DBUG_ENTER("db_drop_routine");
DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name));
TABLE *table;
int ret;
bool opened;
ret= db_find_routine_aux(thd, type, name, namelen, TL_WRITE, &table, &opened);
if (ret == SP_OK)
{
if (table->file->delete_row(table->record[0]))
ret= SP_DELETE_ROW_FAILED;
}
if (opened)
close_thread_tables(thd);
DBUG_RETURN(ret);
}
/*
*
* PROCEDURE
*
*/
sp_head *
sp_find_procedure(THD *thd, LEX_STRING *name)
{
DBUG_ENTER("sp_find_procedure");
sp_head *sp;
DBUG_PRINT("enter", ("name: %*s", name->length, name->str));
if (db_find_routine(thd, TYPE_ENUM_PROCEDURE,
name->str, name->length, &sp) != SP_OK)
sp= NULL;
DBUG_RETURN(sp);
}
int
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen)
{
DBUG_ENTER("sp_create_procedure");
DBUG_PRINT("enter", ("name: %*s def: %*s", namelen, name, deflen, def));
int ret;
ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen, def, deflen);
DBUG_RETURN(ret);
}
int
sp_drop_procedure(THD *thd, char *name, uint namelen)
{
DBUG_ENTER("sp_drop_procedure");
DBUG_PRINT("enter", ("name: %*s", namelen, name));
int ret;
ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen);
DBUG_RETURN(ret);
}
/*
*
* FUNCTION
*
*/
sp_head *
sp_find_function(THD *thd, LEX_STRING *name)
{
DBUG_ENTER("sp_find_function");
sp_head *sp;
DBUG_PRINT("enter", ("name: %*s", name->length, name->str));
sp= sp_find_cached_function(thd, name->str, name->length);
if (! sp)
{
if (db_find_routine(thd, TYPE_ENUM_FUNCTION,
name->str, name->length, &sp) != SP_OK)
sp= NULL;
}
DBUG_RETURN(sp);
}
int
sp_create_function(THD *thd, char *name, uint namelen, char *def, uint deflen)
{
DBUG_ENTER("sp_create_function");
DBUG_PRINT("enter", ("name: %*s def: %*s", namelen, name, deflen, def));
int ret;
ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, name, namelen, def, deflen);
DBUG_RETURN(ret);
}
int
sp_drop_function(THD *thd, char *name, uint namelen)
{
DBUG_ENTER("sp_drop_function");
DBUG_PRINT("enter", ("name: %*s", namelen, name));
int ret;
ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name, namelen);
DBUG_RETURN(ret);
}
// QQ Temporary until the function call detection in sql_lex has been reworked.
bool
sp_function_exists(THD *thd, LEX_STRING *name)
{
TABLE *table;
bool ret= FALSE;
bool opened;
if (db_find_routine_aux(thd, TYPE_ENUM_FUNCTION,
name->str, name->length, TL_READ,
&table, &opened) == SP_OK)
{
ret= TRUE;
}
if (opened)
close_thread_tables(thd);
return ret;
}
/*
*
* The temporary FUNCTION cache. (QQ This will be rehacked later, but
* it's needed now to make functions work at all.)
*
*/
void
sp_add_fun_to_lex(LEX *lex, LEX_STRING fun)
{
List_iterator_fast<char> li(lex->spfuns);
char *fn;
while ((fn= li++))
{
if (strncasecmp(fn, fun.str, fun.length) == 0)
break;
}
if (! fn)
{
char *s= sql_strmake(fun.str, fun.length);
lex->spfuns.push_back(s);
}
}
void
sp_merge_funs(LEX *dst, LEX *src)
{
List_iterator_fast<char> li(src->spfuns);
char *fn;
while ((fn= li++))
{
LEX_STRING lx;
lx.str= fn; lx.length= strlen(fn);
sp_add_fun_to_lex(dst, lx);
}
}
/* QQ Not terribly efficient right now, but it'll do for starters.
We should actually open the mysql.proc table just once. */
int
sp_cache_functions(THD *thd, LEX *lex)
{
List_iterator<char> li(lex->spfuns);
char *fn;
enum_sql_command cmd= lex->sql_command;
int ret= 0;
while ((fn= li++))
{
List_iterator_fast<sp_head> lisp(thd->spfuns);
sp_head *sp;
while ((sp= lisp++))
{
if (strcasecmp(fn, sp->name()) == 0)
break;
}
if (sp)
continue;
if (db_find_routine(thd, TYPE_ENUM_FUNCTION, fn, strlen(fn), &sp) == SP_OK)
{
ret= sp_cache_functions(thd, &thd->lex);
if (ret)
break;
thd->spfuns.push_back(sp);
}
else
{
send_error(thd, ER_SP_DOES_NOT_EXIST);
ret= 1;
}
}
lex->sql_command= cmd;
return ret;
}
void
sp_clear_function_cache(THD *thd)
{
thd->spfuns.empty();
}
static sp_head *
sp_find_cached_function(THD *thd, char *name, uint namelen)
{
List_iterator_fast<sp_head> li(thd->spfuns);
sp_head *sp;
while ((sp= li++))
{
if (strncasecmp(name, sp->name(), namelen) == 0)
break;
}
return sp;
}
/* -*- 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_
// Return codes from sp_create_* and sp_drop_*:
#define SP_OK 0
#define SP_KEY_NOT_FOUND -1
#define SP_OPEN_TABLE_FAILED -2
#define SP_WRITE_ROW_FAILED -3
#define SP_DELETE_ROW_FAILED -4
#define SP_GET_FIELD_FAILED -5
#define SP_PARSE_ERROR -6
sp_head *
sp_find_procedure(THD *thd, LEX_STRING *name);
int
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen);
int
sp_drop_procedure(THD *thd, char *name, uint namelen);
sp_head *
sp_find_function(THD *thd, LEX_STRING *name);
int
sp_create_function(THD *thd, char *name, uint namelen, char *def, uint deflen);
int
sp_drop_function(THD *thd, char *name, uint namelen);
// QQ Temporary until the function call detection in sql_lex has been reworked.
bool
sp_function_exists(THD *thd, LEX_STRING *name);
// QQ More temporary stuff until the real cache is implemented. This is
// needed since we have to read the functions before we do anything else.
void
sp_add_fun_to_lex(LEX *lex, LEX_STRING fun);
void
sp_merge_funs(LEX *dst, LEX *src);
int
sp_cache_functions(THD *thd, LEX *lex);
void
sp_clear_function_cache(THD *thd);
#endif /* _SP_H_ */
This diff is collapsed.
/* -*- 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>
// Values for the type enum. This reflects the order of the enum declaration
// in the CREATE TABLE command.
#define TYPE_ENUM_FUNCTION 1
#define TYPE_ENUM_PROCEDURE 2
Item_result
sp_map_result_type(enum enum_field_types type);
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:
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
enum enum_field_types m_returns; // For FUNCTIONs only
my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
#if 0
// We're not using this at the moment.
List<char *> m_calls; // Called procedures.
List<char *> m_tables; // Used tables.
#endif
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_function(THD *thd, Item **args, uint argcount, Item **resp);
int
execute_procedure(THD *thd, List<Item> *args);
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 *);
char *name(uint *lenp = 0) const
{
String *n= m_name->const_string();
if (lenp)
*lenp= n->length();
return n->c_ptr();
}
inline Item_result result()
{
return sp_map_result_type(m_returns);
}
private:
Item_string *m_name;
Item_string *m_defstr;
sp_pcontext *m_pcont; // Parse context
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 backpatching
inline sp_instr *
get_instr(uint i)
{
sp_instr *in= NULL;
if (i < m_instr.elements)
get_dynamic(&m_instr, (gptr)&in, i);
return in;
}
int
execute(THD *thd);
}; // 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);
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
class sp_instr_return : public sp_instr
{
sp_instr_return(const sp_instr_return &); /* Prevent use of these */
void operator=(sp_instr_return &);
public:
sp_instr_return(uint ip, Item *val, enum enum_field_types type)
: sp_instr(ip), m_value(val), m_type(type)
{}
virtual ~sp_instr_return()
{}
virtual int execute(THD *thd, uint *nextp);
protected:
Item *m_value;
enum enum_field_types m_type;
}; // class sp_instr_return : public sp_instr
#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_result(NULL)
{
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];
}
inline void
set_result(Item *it)
{
m_result= it;
}
inline Item *
get_result()
{
return m_result;
}
private:
uint m_count;
uint m_size;
Item **m_frame;
int *m_outs;
Item *m_result; // For FUNCTIONs
}; // class sp_rcontext : public Sql_alloc
#endif /* _SP_RCONTEXT_H_ */
......@@ -35,6 +35,7 @@
#include <io.h>
#endif
#include <mysys_err.h>
#include <sp_rcontext.h>
/*****************************************************************************
......@@ -80,7 +81,7 @@ extern "C" void free_user_var(user_var_entry *entry)
THD::THD():user_time(0), is_fatal_error(0),
last_insert_id_used(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_or_ip= "connecting host";
......@@ -967,9 +968,12 @@ bool select_exists_subselect::send_data(List<Item> &items)
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
List_iterator_fast<Item> li(list);
List_iterator_fast<LEX_STRING> gl(var_list);
List_iterator_fast<my_var> gl(var_list);
Item *item;
my_var *mv;
LEX_STRING *ls;
row_count= 0;
if (var_list.elements != list.elements)
{
my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, MYF(0));
......@@ -978,19 +982,39 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
unit=u;
while ((item=li++))
{
ls= gl++;
Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item);
xx->fix_fields(thd,(TABLE_LIST*) thd->lex.select_lex.table_list.first,&item);
xx->fix_length_and_dec();
vars.push_back(xx);
mv=gl++;
ls= &mv->s;
if (mv->local)
{
(void)local_vars.push_back(new Item_splocal(mv->offset));
}
else
{
Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item);
xx->fix_fields(thd,(TABLE_LIST*) thd->lex.select_lex.table_list.first,&item);
xx->fix_length_and_dec();
vars.push_back(xx);
}
}
return 0;
}
bool select_dumpvar::send_data(List<Item> &items)
{
List_iterator_fast<Item_func_set_user_var> li(vars);
List_iterator_fast<Item_splocal> var_li(local_vars);
List_iterator_fast<my_var> my_li(var_list);
List_iterator_fast<Item> it(items);
Item_func_set_user_var *xx;
Item_splocal *yy;
Item *item;
my_var *zz;
DBUG_ENTER("send_data");
if (unit->offset_limit_cnt)
{ // using limit offset,count
unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
if (unit->offset_limit_cnt)
{ // Using limit offset,count
......@@ -1002,8 +1026,21 @@ bool select_dumpvar::send_data(List<Item> &items)
my_error(ER_TOO_MANY_ROWS, MYF(0));
DBUG_RETURN(1);
}
while ((xx=li++))
xx->update();
while ((zz=my_li++) && (item=it++))
{
if (zz->local)
{
if ((yy=var_li++))
{
thd->spcont->set_item(yy->get_offset(), item);
}
}
else
{
if ((xx=li++))
xx->update();
}
}
DBUG_RETURN(0);
}
......
......@@ -26,6 +26,7 @@
class Query_log_event;
class Load_log_event;
class Slave_log_event;
class sp_rcontext;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY };
......@@ -550,6 +551,8 @@ class THD :public ilink
bool volatile killed;
bool prepare_command;
bool tmp_table_used;
sp_rcontext *spcont; // SP runtime context
List<sp_head> spfuns; // SP FUNCTIONs
/*
If we do a purge of binary logs, log index info of the threads
......@@ -1019,13 +1022,22 @@ class multi_update : public select_result
bool send_eof();
};
class my_var : public Sql_alloc {
public:
LEX_STRING s;
bool local;
uint offset;
my_var (LEX_STRING& j, bool i, uint o) : s(j), local(i), offset(o) {}
~my_var() {}
};
class select_dumpvar :public select_result {
ha_rows row_count;
public:
List<LEX_STRING> var_list;
List<my_var> var_list;
List<Item_func_set_user_var> vars;
select_dumpvar(void) { var_list.empty(); vars.empty(); row_count=0;}
List<Item_splocal> local_vars;
select_dumpvar(void) { var_list.empty(); local_vars.empty(); vars.empty(); row_count=0;}
~select_dumpvar() {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_fields(List<Item> &list, uint flag) {return 0;}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -191,7 +191,8 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
send_error(thd, 0, NullS);
res= 1;
}
delete result;
if (result != lex->result)
delete result;
return res;
}
......
This diff is collapsed.
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