Merge 4.1 into 5.0 (first pass).

BitKeeper/etc/ignore:
  auto-union
BitKeeper/etc/logging_ok:
  auto-union
BitKeeper/deleted/.del-cron-build:
  Delete: netware/BUILD/cron-build
BitKeeper/deleted/.del-crontab:
  Delete: netware/BUILD/crontab
BitKeeper/triggers/post-commit:
  Auto merged
client/mysql.cc:
  Auto merged
client/mysqltest.c:
  Auto merged
configure.in:
  Auto merged
include/my_global.h:
  Auto merged
include/my_pthread.h:
  Auto merged
include/mysql_com.h:
  Auto merged
libmysqld/Makefile.am:
  Auto merged
myisam/mi_check.c:
  Auto merged
myisam/myisamchk.c:
  Auto merged
myisam/myisamdef.h:
  Auto merged
myisam/sort.c:
  Auto merged
mysql-test/r/connect.result:
  Auto merged
mysql-test/r/rpl_temporary.result:
  Auto merged
mysql-test/r/show_check.result:
  Auto merged
mysql-test/r/variables.result:
  Auto merged
mysql-test/t/subselect.test:
  Auto merged
mysql-test/t/variables.test:
  Auto merged
netware/BUILD/compile-AUTOTOOLS:
  Auto merged
netware/BUILD/compile-linux-tools:
  Auto merged
netware/BUILD/compile-netware-END:
  Auto merged
netware/BUILD/compile-netware-START:
  Auto merged
netware/BUILD/compile-netware-all:
  Auto merged
netware/BUILD/compile-netware-debug:
  Auto merged
netware/BUILD/compile-netware-standard:
  Auto merged
netware/BUILD/mwasmnlm:
  Auto merged
netware/BUILD/mwccnlm:
  Auto merged
netware/BUILD/mwldnlm:
  Auto merged
netware/BUILD/nwbootstrap:
  Auto merged
sql/filesort.cc:
  Auto merged
sql/ha_myisam.cc:
  Auto merged
sql/item.h:
  Auto merged
sql/item_create.cc:
  Auto merged
sql/item_func.h:
  Auto merged
sql/log.cc:
  Auto merged
sql/log_event.cc:
  Auto merged
sql/protocol.cc:
  Auto merged
sql/records.cc:
  Auto merged
sql/repl_failsafe.cc:
  Auto merged
sql/set_var.cc:
  Auto merged
sql/slave.cc:
  Auto merged
sql/sql_acl.cc:
  Auto merged
sql/sql_base.cc:
  Auto merged
sql/sql_class.cc:
  Auto merged
sql/sql_class.h:
  Auto merged
sql/sql_db.cc:
  Auto merged
sql/sql_delete.cc:
  Auto merged
sql/sql_derived.cc:
  Auto merged
sql/sql_error.cc:
  Auto merged
sql/sql_load.cc:
  Auto merged
sql/sql_prepare.cc:
  Auto merged
sql/sql_repl.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/sql_show.cc:
  Auto merged
sql/sql_table.cc:
  Auto merged
sql/sql_union.cc:
  Auto merged
This commit is contained in:
unknown 2003-07-08 17:50:23 +02:00
commit d6b336359a
119 changed files with 6324 additions and 929 deletions

View file

@ -374,6 +374,9 @@ libmysqld/repl_failsafe.cc
libmysqld/set_var.cc
libmysqld/simple-test
libmysqld/slave.cc
libmysqld/sp.cc
libmysqld/sp_head.cc
libmysqld/sp_pcontext.cc
libmysqld/spatial.cc
libmysqld/sql_acl.cc
libmysqld/sql_analyse.cc

View file

@ -83,10 +83,12 @@ paul@central.snake.net
paul@ice.snake.net
paul@teton.kitebird.com
pem@mysql.com
pem@per-erik-martins-dator.local
peter@linux.local
peter@mysql.com
peterg@mysql.com
pgulutzan@linux.local
pmartin@build.mysql2.com
ram@gw.udmsearch.izhnet.ru
ram@mysql.r18.ru
ram@ram.(none)

View file

@ -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

622
Docs/sp-imp-spec.txt Normal file
View file

@ -0,0 +1,622 @@
Implementation specification for Stored Procedures
==================================================
- How parsing and execution of queries work
In order to execute a query, the function sql_parse.cc:mysql_parse() is
called, which in turn calls the parser (yyparse()) with an updated Lex
structure as the result. mysql_parse() then calls mysql_execute_command()
which dispatches on the command code (in Lex) to the corresponding code for
executing that particular query.
There are thre structures involved in the execution of a query which are of
interest to the stored procedure implementation:
- Lex (mentioned above) is the "compiled" query, that is the output from
the parser and what is then interpreted to do the actual work.
It constains an enum value (sql_command) which is the query type, and
all the data collected by the parser needed for the execution (table
names, fields, values, etc).
- THD is the "run-time" state of a connection, containing all that is
needed for a particular client connection, and, among other things, the
Lex structure currently being executed.
- Item_*: During parsing, all data is translated into "items", objects of
the subclasses of "Item", such as Item_int, Item_real, Item_string, etc,
for basic datatypes, and also various more specialized Item types for
expressions to be evaluated (Item_func objects).
- How to fit Stored Procedure into this scheme
- An overview of the classes and files for stored procedures
(More detailed APIs at the end of this file)
- class sp_head (sp_head.{cc,h})
This contains, among other things, an array of "instructions" and the
method for executing the procedure.
- class sp_pcontext (sp_pcontext.{cc,h}
This is the parse context for the procedure. It's primarily used during
parsing to keep track of local parameters, variables and labels, but
it's also used at CALL time do find parameters mode (IN, OUT or INOUT)
and type when setting up the runtime context.
- class sp_instr (sp_head.{cc,h})
This is the base class for "instructions", that is, what is generated
by the parser. It turns out that we only need 4 different sub classes:
- sp_instr_stmt
Execute a statement. This is the "call-out" any normal SQL statement,
like a SELECT, INSERT etc. It contains the Lex structure for the
statement in question.
- sp_instr_set
Set the value of a local variable (or parameter)
- sp_instr_jump
An unconditional jump.
- sp_instr_jump_if_not
Jump if condition is not true. It turns out that the negative test is
most convenient when generating the code for the flow control
constructs.
- class sp_rcontext (sp_rcontext.h)
This is the runtime context in the THD structure.
It contains an array of items, the parameters and local variables for
the currently executing stored procedure.
This means that variable value lookup is in runtime is constant time,
a simple index operation.
- class Item_splocal (Item.{cc,h})
This is a subclass of Item. Its sole purpose is to hide the fact that
the real Item is actually in the current frame (runtime context).
It contains the frame offset and defers all methods to the real Item
in the frame. This is what the parser generates for local variables.
- Utility functions (sp.{cc,h})
This contains functions for creating, dropping and finding a stored
procedure in the mysql.proc table (or internal cache, when it is
implemented).
- Parsing CREATE PROCEDURE ...
When parsing a CREATE PROCEDURE the parser first initializes the
sphead and spcont (runtime context) fields in the Lex.
The sql_command code for the result of parsing a is
SQLCOM_CREATE_PROCEDURE.
The parsing of the parameter list and body is relatively
straight-forward:
- Parameters:
name, type and mode (IN/OUT/INOUT) is pushed to spcont
- Declared local variables:
Same as parameters (mode is then IN)
- Local Variable references:
If an identifier is found in in spcont, an Item_splocal is created
with the variable's frame index, otherwise an Item_field or Item_ref
is created (as before).
- Statements:
The Lex in THD is replaced by a new Lex structure and the statement,
is parsed as usual. A sp_instr_stmt is created, containing the new
Lex, and added to added to the instructions in sphead.
Afterwards, the procedure's Lex is restored in THD.
- SET var:
Setting a local variable generates a sp_instr_set instruction,
containing the variable's frame offset, the expression (an Item),
and the type.
- Flow control:
Flow control constructs like, IF, WHILE, etc, generate a conditional
and unconditional jumps in the "obvious" way, but a few notes may
be required:
- Forward jumps: When jumping forward, the exact destination is not
known at the time of the creation of the jump instruction. The
sphead therefore contains list of instruction-label pairs for
each forward reference. When the position later is known, the
instructions in the list are updated with the correct location.
- Loop constructs have optional labels. If a loop doesn't have a
label, an anonymous label is generated to simplify the parsing.
- There are two types of CASE. The "simple" case is implemented
with an anonymous variable bound to the value to be tested.
- An example
Parsing the procedure:
create procedure a(s char(16))
begin
declare x int;
set x = 3;
while x > 0 do
set x = x-1;
insert into db.tab values (x, s);
end while
end
would generate the following structures:
______
thd: | | _________
| lex -+--->| | ___________________
|______| | spcont -+------------------->| "s",in,char(16):0 |
| sphead -+------ |("x",in,int :1)|
|_________| | |___________________|
____V__________________
| m_name: "a" |
| m_defstr: "create ..."|
| m_instr: ... |
|_______________________|
Note that the contents of the spcont is changing during the parsing,
at all times reflecting the state of the would-be runtime frame.
The m_instr is an array of instructions:
Pos. Instruction
0 sp_instr_set(1, '3')
1 sp_instr_jump_if_not(5, 'x>0')
2 sp_instr_set(1, 'x-1')
3 sp_instr_stmt('insert into ...')
4 sp_instr_jump(1)
5 <end>
Here, '3', 'x>0', etc, represent the Items or Lex for the respective
expressions or statements.
- Parsing CREATE FUNCTION ...
Creating a functions is essensially the same thing as for a PROCEDURE,
with the addition that a FUNCTION has a return type and a RETURN
statement, but no OUT or INOUT parameters.
The main difference during parsing is that we store the result type
in the sp_head. However, there are big differences when it comes to
invoking a FUNCTION. (See below.)
- Storing, caching, dropping...
As seen above, the entired definition string, including the "CREATE
PROCEDURE" (or "FUNCTION") is kept. The procedure definition string is
stored in the table mysql.proc with the name and type as the key, the
type being one of the enum ("procedure","function").
A PROCEDURE is just stored int the mysql.proc table. A FUNCTION has an
additional requirement. They will be called in expressions with the same
syntax as UDFs, so UDFs and stored FUNCTIONs share the namespace. Thus,
we must make sure that we do not have UDFs and FUNCTIONs with the same
name (even if they are storded in different places).
This means that we can reparse the procedure as many time as we want.
The first time, the resulting Lex is used to store the procedure in
the database (using the function sp.c:sp_create_procedure()).
The simplest way would be to just leave it at that, and re-read the
procedure from the database each time it is called. (And in fact, that's
the way the earliest implementation will work.)
However, this is not very efficient, and we can do better. The full
implementation should work like this:
1) Upon creation time, parse and store the procedure. Note that we still
need to parse it to catch syntax errors, but we can't check if called
procedures exists for instance.
2) Upon first CALL, read from the database, parse it, and cache the
resulting Lex in memory. This time we can do more error checking.
3) Upon subsequent CALLs, use the cached Lex.
Note that this implies that the Lex structure with its sphead must be
reentrant, that is, reusable and shareable between different threads
and calls. The runtime state for a procedure is kept in the sp_rcontext
in THD.
The mechanisms of storing, finding, and dropping procedures are
encapsulated in the files sp.{cc,h}.
- CALLing a procedure
A CALL is parsed just like any statement. The resulting Lex has the
sql_command SQLCOM_CALL, the procedure's name and the parameters are
pushed to the Lex' value_list.
sql_parse.cc:mysql_execute_command() then uses sp.cc:sp_find() to
get the sp_head for the procedure (which may have been read from the
database or feetched from the in-memory cache) and calls the sp_head's
method execute().
Note: It's important that substatements called by the procedure do not
do send_ok(). Fortunately, there is a flag in THD->net to disable
this during CALLs. If a substatement fails, it will however send
an error back to the client, so the CALL mechanism must return
immediately and without sending an error.
The sp_head::execute() method works as follows:
1) Keep a pointer to the old runtime context in THD (if any)
2) Create a new runtime context. The information about the required size
is in sp_head's parse time context.
3) Push each parameter (from the CALL's Lex->value_list) to the new
context. If it's an OUT or INOUT parameter, the parameter's offset
in the caller's frame is set in the new context as well.
4) For each instruction, call its execute() method.
The result is a pointer to the next instruction to execute (or NULL)
if an error occured.
5) On success, set the new values of the OUT and INOUT parameters in
the caller's frame.
- USE database
Before executing the instruction we also keeps the current default
database (if any). If this was changed during execution (i.e. a "USE"
statement has been executed), we restore the current database to the
original.
This is the most useful way to handle USE in procedures. If we didn't,
the caller would find himself in a different database after calling
a function, which can be confusing.
Restoring the database also gives full freedom to the procedure writer:
- It's possible to write "general" procedures that are independent of
the actual database name.
- It's possible to write procedures that work on a particular database
by calling USE, without having to use fully qualified table names
everywhere (which doesn't help if you want to call other, "general",
procedures anyway).
- Evaluating Items
There are three occasions where we need to evaluate an expression:
- When SETing a variable
- When CALLing a procedure
- When testing an expression for a branch (in IF, WHILE, etc)
The semantics in stored procedures is "call-by-value", so we have to
evaluate any "func" Items at the point of the CALL or SET, otherwise
we would get a kind of "lazy" evaluation with unexpected results with
respect to OUT parameters for instance.
For this the support function, sp_head.cc:eval_func_item() is needed.
- Calling a FUNCTION
Functions don't have an explicit call keyword like procedures. Instead,
they appear in expressions with the conventional syntax "fun(arg, ...)".
The problem is that we already have User Defined Functions (UDFs) which
are called the same way. A UDF is detected by the lexical analyzer (not
the parser!), in the find_keyword() function, and returns a UDF_*_FUNC
or UDA_*_SUM token with the udf_func object as the yylval.
So, stored functions must be handled in a simpilar way, and as a
consequence, UDFs and functions must not have the same name.
- Detecting and parsing a FUNCTION invokation
The existance of UDFs are checked during the lexical analysis (in
sql_lex.cc:find_keyword()). This has the drawback that they must
exist before they are refered to, which was ok before SPs existed,
but then it becomes a problem. The first implementation of SP FUNCTIONs
will work the same way, but this should be fixed a.s.a.p. (This will
required some reworking of the way UDFs are handled, which is why it's
not done from the start.)
For the time being, a FUNCTION is detected the same way, and returns
the token SP_FUNC. During the parsing we only check for the *existance*
of the function, we don't parse it, since wa can't call the parser
recursively.
When encountering a SP_FUNC with parameters in the expression parser,
an instance of the new Item_func_sp class is created. Unlike UDFs, we
don't have different classes for different return types, since we at
this point don't know the type.
- Collecting FUNCTIONs to invoke
A FUNCTION differs from a PROCEDURE in one important aspect: Whereas a
PROCEDURE is CALLed as statement by itself, a FUNCTION is invoked
"on-the-fly" during the execution of *another* statement.
This makes things a lot more complicated compared to CALL:
- We can't read and parse the FUNCTION from the mysql.proc table at the
point of invokation; the server requires that all tables used are
opened and locked at the beginning of the query execution.
One "obvious" solution would be to simply push "mysql.proc" to the list
of tables used by the query, but this implies a "join" with this table
if the query is a select, so it doesn't work (and we can't exclude this
table easily; since a priviledged used might in fact want to search
the proc table).
Another solution would of course be to allow the opening and closing
of the mysql.proc table during a query execution, but this it not
possible at the present.
So, the solution is to collect the names of the refered FUNCTIONs during
parsing in the lex.
Then, before doing anything else in mysql_execute_command(), read all
functions from the database an keep them in the THD, where the function
sp_find_function() can find them during the execution.
Note: Even when a global in-memory cache is implemented, we must still
make sure that the functions are indeed read and cached at this point.
The code that read and cache functions from the database must also be
invoked recursively for each read FUNCTION to make sure we have *all* the
functions we need.
In the absence of the real in-memory cache for SPs, a temporary solution
has been implemented with a per-THD cache for just FUNCTIONs. This is
handled by the functions
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);
in sp.cc.
- Parsing DROP PROCEDURE/FUNCTION
The procedure name is pushed to Lex->value_list.
The sql_command code for the result of parsing a is
SQLCOM_DROP_PROCEDURE/SQLCOM_DROP_FUNCTION.
Dropping is done by simply getting the procedure with the sp_find()
function and calling sp_drop() (both in sp.{cc,h}).
DROP PROCEDURE/FUNCTION also supports the non-standard "IF EXISTS",
analogous to other DROP statements in MySQL.
- Class and function APIs
- The parser context: sp_pcontext.h
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;
class sp_pcontext
{
sp_pcontext();
// Return the maximum frame size
uint max_framesize();
// Return the current frame size
uint current_framesize();
// Return the number of parameters
uint params();
// Set the number of parameters to the current frame size
void set_params();
// Set type of the variable at offset 'i' in the frame
void set_type(uint i, enum enum_field_types type);
// Mark the i:th variable to "set" (i.e. having a value) with
// 'val' true.
void set_isset(uint i, my_bool val);
// Push the variable 'name' to the frame.
void push(LEX_STRING *name,
enum enum_field_types type, sp_param_mode_t mode);
// Pop 'num' variables from the frame.
void pop(uint num = 1);
// Find variable by name
sp_pvar_t *find_pvar(LEX_STRING *name);
// Find variable by index
sp_pvar_t *find_pvar(uint i);
// Push label 'name' of instruction index 'ip' to the label context
sp_label_t *push_label(char *name, uint ip);
// Find label 'name' in the context
sp_label_t *find_label(char *name);
// Return the last pushed label
sp_label_t *last_label();
// Return and remove the last pushed label.
sp_label_t *pop_label();
}
- The run-time context (call frame): sp_rcontext.h
class sp_rcontext
{
// 'size' is the max size of the context
sp_rcontext(uint size);
// Push value (parameter) 'i' to the frame
void push_item(Item *i);
// Set slot 'idx' to value 'i'
void set_item(uint idx, Item *i);
// Return the item in slot 'idx'
Item *get_item(uint idx);
// Set the "out" index 'oidx' for slot 'idx. If it's an IN slot,
// use 'oidx' -1.
void set_oindex(uint idx, int oidx);
// Return the "out" index for slot 'idx'
int get_oindex(uint idx);
// Set the FUNCTION result
void set_result(Item *i);
// Get the FUNCTION result
Item *get_result();
}
- The procedure: sp_head.h
#define TYPE_ENUM_FUNCTION 1
#define TYPE_ENUM_PROCEDURE 2
class sp_head
{
int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
sp_head(LEX_STRING *name, LEX*);
// Store this procedure in the database. This is a wrapper around
// the function sp_create_procedure().
int create(THD *);
// Invoke a FUNCTION
int
execute_function(THD *thd, Item **args, uint argcount, Item **resp);
// CALL a PROCEDURE
int
execute_procedure(THD *thd, List<Item> *args);
// Add the instruction to this procedure.
void add_instr(sp_instr *);
// Return the number of instructions.
uint instructions();
// Resets lex in 'thd' and keeps a copy of the old one.
void reset_lex(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 *);
// 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 *);
}
- Instructions
- The base class:
class sp_instr
{
// 'ip' is the index of this instruction
sp_instr(uint ip);
// 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 *, uint *nextp)
}
- Statement instruction:
class sp_instr_stmt : public sp_instr
{
sp_instr_stmt(uint ip);
int execute(THD *, uint *nextp);
// Set the statement's Lex
void set_lex(LEX *);
// Return the statement's Lex
LEX *get_lex();
}
- SET instruction:
class sp_instr_set : public sp_instr
{
// 'offset' is the variable's frame offset, 'val' the value,
// and 'type' the variable type.
sp_instr_set(uint ip,
uint offset, Item *val, enum enum_field_types type);
int execute(THD *, uint *nextp);
}
- Unconditional jump
class sp_instr_jump : public sp_instr
{
// No destination, must be set.
sp_instr_jump(uint ip);
// 'dest' is the destination instruction index.
sp_instr_jump(uint ip, uint dest);
int execute(THD *, uint *nextp);
// Set the destination instruction 'dest'.
void set_destination(uint dest);
}
- Conditional jump
class sp_instr_jump_if_not : public sp_instr_jump
{
// Jump if 'i' evaluates to false. Destination not set yet.
sp_instr_jump_if_not(uint ip, Item *i);
// Jump to 'dest' if 'i' evaluates to false.
sp_instr_jump_if_not(uint ip, Item *i, uint dest)
int execute(THD *, uint *nextp);
}
- Return a function value
class sp_instr_return : public sp_instr
{
// Return the value 'val'
sp_instr_return(uint ip, Item *val, enum enum_field_types type);
int execute(THD *thd, uint *nextp);
}
- Utility functions: sp.h
#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
// Finds a stored procedure given its name. Returns NULL if not found.
sp_head *sp_find_procedure(THD *, LEX_STRING *name);
// Store the procedure 'name' in the database. 'def' is the complete
// definition string ("create procedure ...").
int sp_create_procedure(THD *,
char *name, uint namelen,
char *def, uint deflen);
// Drop the procedure 'name' from the database.
int sp_drop_procedure(THD *, char *name, uint namelen);
// Finds a stored function given its name. Returns NULL if not found.
sp_head *sp_find_function(THD *, LEX_STRING *name);
// Store the function 'name' in the database. 'def' is the complete
// definition string ("create function ...").
int sp_create_function(THD *,
char *name, uint namelen,
char *def, uint deflen);
// Drop the function 'name' from the database.
int sp_drop_function(THD *, char *name, uint namelen);
--

99
Docs/sp-implemented.txt Normal file
View file

@ -0,0 +1,99 @@
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 [IF EXISTS] 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.

View file

@ -2808,6 +2808,7 @@ void tee_fprintf(FILE *file, const char *fmt, ...)
{
va_list args;
NETWARE_YIELD
va_start(args, fmt);
(void) vfprintf(file, fmt, args);
#ifdef OS2
@ -2821,6 +2822,7 @@ void tee_fprintf(FILE *file, const char *fmt, ...)
void tee_fputs(const char *s, FILE *file)
{
NETWARE_YIELD
fputs(s, file);
#ifdef OS2
fflush( file);
@ -2832,6 +2834,7 @@ void tee_fputs(const char *s, FILE *file)
void tee_puts(const char *s, FILE *file)
{
NETWARE_YIELD
fputs(s, file);
fputs("\n", file);
#ifdef OS2

View file

@ -90,6 +90,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,
@ -127,6 +128,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;
#include "sslopt-vars.h"
@ -203,7 +206,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
@ -267,6 +270,7 @@ const char *command_names[]=
"disable_warnings",
"enable_info",
"disable_info",
"delimiter",
0
};
@ -1545,6 +1549,16 @@ int do_while(struct st_query* q)
return 0;
}
int do_delimiter(char *p)
{
while (*p && my_isspace(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)
{
@ -1624,7 +1638,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;
@ -1664,7 +1678,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;
@ -1684,7 +1698,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;
@ -1705,7 +1719,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;
@ -2575,6 +2589,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:
break;

View file

@ -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.1-alpha)
AM_INIT_AUTOMAKE(mysql, 5.0.0-alpha)
AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10
@ -36,7 +36,7 @@ for i in $AVAILABLE_LANGUAGES
do
AVAILABLE_LANGUAGES_ERRORS="$AVAILABLE_LANGUAGES_ERRORS $i/errmsg.sys"
case $host_os in
netware* | modesto*)
netware*)
echo "$i/errmsg.sys: $i/errmsg.txt
\$(top_builddir)/extra/comp_err.linux \$^ $i/errmsg.sys" \
>> $AVAILABLE_LANGUAGES_ERRORS_RULES
@ -458,7 +458,7 @@ else
*cygwin*)
FIND_PROC="$PS -e | grep mysqld | grep \" \$\$PID \" > /dev/null"
;;
*netware* | *modesto*)
*netware*)
FIND_PROC=
;;
*)
@ -1539,7 +1539,7 @@ AC_SUBST(LIBDL)
# System characteristics
case $SYSTEM_TYPE in
*netware* | *modesto*) ;;
*netware*) ;;
*)
AC_SYS_RESTARTABLE_SYSCALLS
;;
@ -1569,10 +1569,12 @@ else
fi
if expr "$SYSTEM_TYPE" : ".*netware.*" > /dev/null; then
DEBUG_CFLAGS="$DEBUG_CFLAGS -DDEBUG -sym internal,codeview4"
DEBUG_CXXFLAGS="$DEBUG_CXXFLAGS -DDEBUG -sym internal,codeview4"
OPTIMIZE_CFLAGS="$OPTIMIZE_CFLAGS -DNDEBUG"
OPTIMIZE_CXXFLAGS="$OPTIMIZE_CXXFLAGS -DNDEBUG"
DEBUG_CFLAGS="-g -DDEBUG -sym internal,codeview4"
DEBUG_CXXFLAGS="-g -DDEBUG -sym internal,codeview4"
DEBUG_OPTIMIZE_CC="-DDEBUG"
DEBUG_OPTIMIZE_CXX="-DDEBUG"
OPTIMIZE_CFLAGS="-O3 -DNDEBUG"
OPTIMIZE_CXXFLAGS="-O3 -DNDEBUG"
fi
AC_ARG_WITH(debug,

View file

@ -14,7 +14,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Defines for netware compatible with MySQL */
/* Header for NetWare compatible with MySQL */
#ifndef _config_netware_h
#define _config_netware_h
/* required headers */
#include <unistd.h>
@ -32,6 +35,10 @@
#include <pthread.h>
#include <termios.h>
#ifdef __cplusplus
extern "C" {
#endif
/* required adjustments */
#undef HAVE_READDIR_R
#undef HAVE_RWLOCK_INIT
@ -80,6 +87,15 @@
/* do not use the extended time in LibC sys\stat.h */
#define _POSIX_SOURCE
/* Some macros for portability */
/* kernal call on NetWare that will only yield if our time slice is up */
void kYieldIfTimeSliceUp(void);
/* some macros for portability */
#define set_timespec(ABSTIME,SEC) { (ABSTIME).tv_sec=(SEC); (ABSTIME).tv_nsec=0; }
#ifdef __cplusplus
}
#endif
#endif /* _config_netware_h */

View file

@ -69,6 +69,13 @@
#endif
#endif /* _WIN32... */
/* extra protection against CPU Hogs on NetWare */
#ifdef __NETWARE__
#define NETWARE_YIELD { kYieldIfTimeSliceUp(); }
#else
#define NETWARE_YIELD { }
#endif
/*
The macros below are borrowed from include/linux/compiler.h in the
Linux kernel. Use them to indicate the likelyhood of the truthfulness

View file

@ -123,6 +123,8 @@ enum enum_server_command
#define NET_WRITE_TIMEOUT 60 /* Timeout on write */
#define NET_WAIT_TIMEOUT 8*60*60 /* Wait for new query */
#define ONLY_KILL_QUERY 1
struct st_vio; /* Only C */
typedef struct st_vio Vio;

View file

@ -286,4 +286,20 @@
#define ER_REVOKE_GRANTS 1267
#define ER_CANT_AGGREGATE_3COLLATIONS 1268
#define ER_CANT_AGGREGATE_NCOLLATIONS 1269
#define ER_ERROR_MESSAGES 270
#define ER_SP_NO_RECURSIVE_CREATE 1270
#define ER_SP_ALREADY_EXISTS 1271
#define ER_SP_DOES_NOT_EXIST 1272
#define ER_SP_DROP_FAILED 1273
#define ER_SP_STORE_FAILED 1274
#define ER_SP_LILABEL_MISMATCH 1275
#define ER_SP_LABEL_REDEFINE 1276
#define ER_SP_LABEL_MISMATCH 1277
#define ER_SP_UNINIT_VAR 1278
#define ER_SP_BADSELECT 1279
#define ER_SP_BADRETURN 1280
#define ER_SP_BADQUERY 1281
#define ER_UPDATE_LOG_DEPRECATED_IGNORED 1282
#define ER_UPDATE_LOG_DEPRECATED_TRANSLATED 1283
#define ER_QUERY_INTERRUPTED 1284
#define ER_SP_WRONG_NO_OF_ARGS 1285
#define ER_ERROR_MESSAGES 286

View file

@ -3205,6 +3205,7 @@ static MYSQL_DATA *read_binary_rows(MYSQL_STMT *stmt)
if (pkt_len > 1)
{
mysql->warning_count= uint2korr(cp+1);
mysql->server_status= uint2korr(cp+3);
DBUG_PRINT("info",("warning_count: %ld", mysql->warning_count));
}
DBUG_PRINT("exit",("Got %d rows",result->rows));

View file

@ -55,7 +55,8 @@ sqlsources = 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 sp_cache.cc
EXTRA_DIST = lib_vio.c

View file

@ -2603,7 +2603,7 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param)
char llbuff[22],llbuff2[22];
DBUG_ENTER("sort_get_next_record");
if (*killed_ptr(param))
if (*killed_ptr(param->thd))
DBUG_RETURN(1);
switch (share->data_file_type) {

View file

@ -1646,9 +1646,9 @@ err:
DBUG_RETURN(1);
} /* sort_record_index */
volatile bool *killed_ptr(MI_CHECK *param)
int *killed_ptr(void *thd)
{
return (bool *)(& param->thd); /* always NULL */
return (int *)thd; /* always NULL */
}
/* print warnings and errors */

View file

@ -695,7 +695,7 @@ int mi_open_keyfile(MYISAM_SHARE *share);
void mi_setup_functions(register MYISAM_SHARE *share);
/* Functions needed by mi_check */
volatile bool *killed_ptr(MI_CHECK *param);
int *killed_ptr(void *thd);
void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_warning _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_info _VARARGS((MI_CHECK *param, const char *fmt,...));

View file

@ -848,7 +848,8 @@ merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file,
uchar *strpos;
BUFFPEK *buffpek,**refpek;
QUEUE queue;
volatile bool *killed= killed_ptr(info->sort_info->param);
int *killed= killed_ptr(info->sort_info->param->thd);
DBUG_ENTER("merge_buffers");
count=error=0;

View file

@ -8,6 +8,7 @@ help_keyword
help_relation
help_topic
host
proc
tables_priv
user
show tables;
@ -24,6 +25,7 @@ help_keyword
help_relation
help_topic
host
proc
tables_priv
user
show tables;
@ -40,6 +42,7 @@ help_keyword
help_relation
help_topic
host
proc
tables_priv
user
show tables;

View file

@ -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;

View file

@ -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;

View file

@ -0,0 +1,98 @@
delete from mysql.proc;
create procedure syntaxerror(t int);
You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
create procedure syntaxerror(t int);
You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
create procedure syntaxerror(t int);
You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
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
drop procedure proc1;
drop function func1;
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
drop procedure if exists foo;
Warnings:
Warning 1261 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()
begin
select name from mysql.proc;
select type from mysql.proc;
end;
call foo();
SELECT in a stored procedure must have INTO
drop procedure foo;
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
create procedure p(x int)
insert into test.t1 values (x);
create function f(x int) returns int
return x+42;
call p();
Wrong number of arguments for PROCEDURE p, expected 1, got 0
call p(1, 2);
Wrong number of arguments for PROCEDURE p, expected 1, got 2
select f();
Wrong number of arguments for FUNCTION f, expected 1, got 0
select f(1, 2);
Wrong number of arguments for FUNCTION f, expected 1, got 2
drop procedure p;
drop function f;

555
mysql-test/r/sp.result Normal file
View file

@ -0,0 +1,555 @@
use test;
drop table if exists t1;
drop table if exists t2;
create table t1 (
id char(16) not null,
data int not null
);
create table t2 (
s char(16) not null,
i int not null,
d double not null
);
create procedure foo42()
insert into test.t1 values ("foo", 42);
call foo42();
select * from t1;
id data
foo 42
delete from t1;
drop procedure foo42;
create procedure u()
use sptmp;
drop database if exists sptmp;
create database sptmp;
use test;
call u();
select database();
database()
test
drop database sptmp;
drop procedure u;
create procedure bar(x char(16), y int)
insert into test.t1 values (x, y);
call bar("bar", 666);
select * from t1;
id data
bar 666
delete from t1;
create procedure two(x1 char(16), x2 char(16), y int)
begin
insert into test.t1 values (x1, y);
insert into test.t1 values (x2, y);
end;
call two("one", "two", 3);
select * from t1;
id data
one 3
two 3
delete from t1;
drop procedure two;
create procedure locset(x char(16), y int)
begin
declare z1, z2 int;
set z1 = y;
set z2 = z1+2;
insert into test.t1 values (x, z2);
end;
call locset("locset", 19);
select * from t1;
id data
locset 21
delete from t1;
drop procedure locset;
create procedure mixset(x char(16), y int)
begin
declare z int;
set @z = y, z = 666, max_join_size = 100;
insert into test.t1 values (x, z);
end;
call mixset("mixset", 19);
show variables like 'max_join_size';
Variable_name Value
max_join_size 100
select id,data,@z from t1;
id data @z
mixset 666 19
delete from t1;
drop procedure mixset;
create procedure zip(x char(16), y int)
begin
declare z int;
call zap(y, z);
call bar(x, z);
end;
create procedure zap(x int, out y int)
begin
declare z int;
set z = x+1, y = z;
end;
call zip("zip", 99);
select * from t1;
id data
zip 100
delete from t1;
drop procedure zip;
drop procedure zap;
drop procedure bar;
create procedure c1(x int)
call c2("c", x);
create procedure c2(s char(16), x int)
call c3(x, s);
create procedure c3(x int, s char(16))
call c4("level", x, s);
create procedure c4(l char(8), x int, s char(16))
insert into t1 values (concat(l,s), x);
call c1(42);
select * from t1;
id data
levelc 42
delete from t1;
drop procedure c1;
drop procedure c2;
drop procedure c3;
drop procedure c4;
create procedure iotest(x1 char(16), x2 char(16), y int)
begin
call inc2(x2, y);
insert into test.t1 values (x1, y);
end;
create procedure inc2(x char(16), y int)
begin
call inc(y);
insert into test.t1 values (x, y);
end;
create procedure inc(inout io int)
set io = io + 1;
call iotest("io1", "io2", 1);
select * from t1;
id data
io2 2
io1 1
delete from t1;
drop procedure iotest;
drop procedure inc2;
drop procedure inc;
create procedure cbv1()
begin
declare y int default 3;
call cbv2(y+1, y);
insert into test.t1 values ("cbv1", y);
end;
create procedure cbv2(y1 int, inout y2 int)
begin
set y2 = 4711;
insert into test.t1 values ("cbv2", y1);
end;
call cbv1();
select * from t1;
id data
cbv2 4
cbv1 4711
delete from t1;
drop procedure cbv1;
drop procedure cbv2;
insert into t2 values ("a", 1, 1.1), ("b", 2, 1.2), ("c", 3, 1.3);
create procedure sub1(id char(16), x int)
insert into test.t1 values (id, x);
create function sub3(i int) returns int
return i+1;
call sub1("sub1a", (select 7));
call sub1("sub1b", (select max(i) from t2));
call sub1("sub1c", (select i,d from t2 limit 1));
call sub1("sub1d", (select 1 from (select 1) a));
select * from t1;
id data
sub1a 7
sub1b 3
sub1c 1
sub1d 1
select sub3((select max(i) from t2));
sub3((select max(i) from t2))
4
drop procedure sub1;
drop function sub3;
create procedure a0(x int)
while x do
set x = x-1;
insert into test.t1 values ("a0", x);
end while;
call a0(3);
select * from t1;
id data
sub1a 7
sub1b 3
sub1c 1
sub1d 1
a0 2
a0 1
a0 0
delete from t1;
drop procedure a0;
create procedure a(x int)
while x > 0 do
set x = x-1;
insert into test.t1 values ("a", x);
end while;
call a(3);
select * from t1;
id data
a 2
a 1
a 0
delete from t1;
drop procedure a;
create procedure b(x int)
repeat
insert into test.t1 values (repeat("b",3), x);
set x = x-1;
until x = 0 end repeat;
call b(3);
select * from t1;
id data
bbb 3
bbb 2
bbb 1
delete from t1;
drop procedure b;
create procedure b2(x int)
repeat(select 1 into outfile 'b2');
insert into test.t1 values (repeat("b2",3), x);
set x = x-1;
until x = 0 end repeat;
drop procedure b2;
create procedure c(x int)
hmm: while x > 0 do
insert into test.t1 values ("c", x);
set x = x-1;
iterate hmm;
insert into test.t1 values ("x", x);
end while hmm;
call c(3);
select * from t1;
id data
c 3
c 2
c 1
delete from t1;
drop procedure c;
create procedure d(x int)
hmm: while x > 0 do
insert into test.t1 values ("d", x);
set x = x-1;
leave hmm;
insert into test.t1 values ("x", x);
end while hmm;
call d(3);
select * from t1;
id data
d 3
delete from t1;
drop procedure d;
create procedure e(x int)
foo: loop
if x = 0 then
leave foo;
end if;
insert into test.t1 values ("e", x);
set x = x-1;
end loop foo;
call e(3);
select * from t1;
id data
e 3
e 2
e 1
delete from t1;
drop procedure e;
create procedure f(x int)
if x < 0 then
insert into test.t1 values ("f", 0);
elseif x = 0 then
insert into test.t1 values ("f", 1);
else
insert into test.t1 values ("f", 2);
end if;
call f(-2);
call f(0);
call f(4);
select * from t1;
id data
f 0
f 1
f 2
delete from t1;
drop procedure f;
create procedure g(x int)
case
when x < 0 then
insert into test.t1 values ("g", 0);
when x = 0 then
insert into test.t1 values ("g", 1);
else
insert into test.t1 values ("g", 2);
end case;
call g(-42);
call g(0);
call g(1);
select * from t1;
id data
g 0
g 1
g 2
delete from t1;
drop procedure g;
create procedure h(x int)
case x
when 0 then
insert into test.t1 values ("h0", x);
when 1 then
insert into test.t1 values ("h1", x);
else
insert into test.t1 values ("h?", x);
end case;
call h(0);
call h(1);
call h(17);
select * from t1;
id data
h0 0
h1 1
h? 17
delete from t1;
drop procedure h;
create procedure into_test(x char(16), y int)
begin
insert into test.t1 values (x, y);
select id,data into x,y from test.t1 limit 1;
insert into test.t1 values (concat(x, "2"), y+2);
end;
call into_test("into", 100);
select * from t1;
id data
into 100
into2 102
delete from t1;
drop procedure into_test;
create procedure into_test2(x char(16), y int)
begin
insert into test.t1 values (x, y);
select id,data into x,@z from test.t1 limit 1;
insert into test.t1 values (concat(x, "2"), y+2);
end;
call into_test2("into", 100);
select id,data,@z from t1;
id data @z
into 100 100
into2 102 100
delete from t1;
drop procedure into_test2;
create procedure into_outfile(x char(16), y int)
begin
insert into test.t1 values (x, y);
select * into outfile "/tmp/spout" from test.t1;
insert into test.t1 values (concat(x, "2"), y+2);
end;
call into_outfile("ofile", 1);
delete from t1;
drop procedure into_outfile;
create procedure into_dumpfile(x char(16), y int)
begin
insert into test.t1 values (x, y);
select * into dumpfile "/tmp/spdump" from test.t1 limit 1;
insert into test.t1 values (concat(x, "2"), y+2);
end;
call into_dumpfile("dfile", 1);
delete from t1;
drop procedure into_dumpfile;
create procedure create_select(x char(16), y int)
begin
insert into test.t1 values (x, y);
create table test.t3 select * from test.t1;
insert into test.t3 values (concat(x, "2"), y+2);
end;
drop table if exists t3;
call create_select("cs", 90);
select * from t1, t3;
id data id data
cs 90 cs 90
cs 90 cs2 92
drop table if exists t3;
delete from t1;
drop procedure create_select;
create function e() returns double
return 2.7182818284590452354;
set @e = e();
select e(), @e;
e() @e
2.718281828459 2.718281828459
create function inc(i int) returns int
return i+1;
select inc(1), inc(99), inc(-71);
inc(1) inc(99) inc(-71)
2 100 -70
create function mul(x int, y int) returns int
return x*y;
select mul(1,1), mul(3,5), mul(4711, 666);
mul(1,1) mul(3,5) mul(4711, 666)
1 15 3137526
create function append(s1 char(8), s2 char(8)) returns char(16)
return concat(s1, s2);
select append("foo", "bar");
append("foo", "bar")
foobar
create function fac(n int unsigned) returns bigint unsigned
begin
declare f bigint unsigned default 1;
while n > 1 do
set f = f * n;
set n = n - 1;
end while;
return f;
end;
select fac(1), fac(2), fac(5), fac(10);
fac(1) fac(2) fac(5) fac(10)
1 2 120 3628800
create function fun(d double, i int, u int unsigned) returns double
return mul(inc(i), fac(u)) / e();
select fun(2.3, 3, 5);
fun(2.3, 3, 5)
176.58213176229
insert into t2 values (append("xxx", "yyy"), mul(4,3), e());
insert into t2 values (append("a", "b"), mul(2,mul(3,4)), fun(1.7, 4, 6));
select * from t2 where s = append("a", "b");
s i d
ab 24 1324.36598821719
select * from t2 where i = mul(4,3) or i = mul(mul(3,4),2);
s i d
xxxyyy 12 2.71828182845905
ab 24 1324.36598821719
select * from t2 where d = e();
s i d
xxxyyy 12 2.71828182845905
select * from t2;
s i d
a 1 1.1
b 2 1.2
c 3 1.3
xxxyyy 12 2.71828182845905
ab 24 1324.36598821719
delete from t2;
drop function e;
drop function inc;
drop function mul;
drop function append;
drop function fun;
drop table if exists fac;
create table fac (n int unsigned not null primary key, f bigint unsigned);
create procedure ifac(n int unsigned)
begin
declare i int unsigned default 1;
if n > 20 then
set n = 20; # bigint overflow otherwise
end if;
while i <= n do
begin
insert into test.fac values (i, fac(i));
set i = i + 1;
end;
end while;
end;
call ifac(20);
select * from fac;
n f
1 1
2 2
3 6
4 24
5 120
6 720
7 5040
8 40320
9 362880
10 3628800
11 39916800
12 479001600
13 6227020800
14 87178291200
15 1307674368000
16 20922789888000
17 355687428096000
18 6402373705728000
19 121645100408832000
20 2432902008176640000
drop table fac;
drop procedure ifac;
drop function fac;
drop table if exists primes;
create table primes (
i int unsigned not null primary key,
p bigint unsigned not null
);
insert into primes values
( 0, 3), ( 1, 5), ( 2, 7), ( 3, 11), ( 4, 13),
( 5, 17), ( 6, 19), ( 7, 23), ( 8, 29), ( 9, 31),
(10, 37), (11, 41), (12, 43), (13, 47), (14, 53),
(15, 59), (16, 61), (17, 67), (18, 71), (19, 73),
(20, 79), (21, 83), (22, 89), (23, 97), (24, 101),
(25, 103), (26, 107), (27, 109), (28, 113), (29, 127),
(30, 131), (31, 137), (32, 139), (33, 149), (34, 151),
(35, 157), (36, 163), (37, 167), (38, 173), (39, 179),
(40, 181), (41, 191), (42, 193), (43, 197), (44, 199);
create procedure opp(n bigint unsigned, out pp bool)
begin
declare r double;
declare b, s bigint unsigned default 0;
set r = sqrt(n);
again:
loop
if s = 45 then
set b = b+200, s = 0;
else
begin
declare p bigint unsigned;
select t.p into p from test.primes t where t.i = s;
if b+p > r then
set pp = 1;
leave again;
end if;
if mod(n, b+p) = 0 then
set pp = 0;
leave again;
end if;
set s = s+1;
end;
end if;
end loop again;
end;
create procedure ip(m int unsigned)
begin
declare p bigint unsigned;
declare i int unsigned;
set i=45, p=201;
while i < m do
begin
declare pp bool default 0;
call opp(p, pp);
if pp then
insert into test.primes values (i, p);
set i = i+1;
end if;
set p = p+2;
end;
end while;
end;
call ip(200);
select * from primes where i=45 or i=100 or i=199;
i p
45 211
100 557
199 1229
drop table primes;
drop procedure opp;
drop procedure ip;
drop table t1;
drop table t2;

View file

@ -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;

View file

@ -1,8 +1,30 @@
drop table if exists t1,t2;
set @`test`=1,@TEST=3,@select=2,@t5=1.23456;
select @test,@`select`,@TEST,@not_used;
@test @`select` @TEST @not_used
1 2 3 NULL
set @`test`=1;
select @test, @`test`, @TEST, @`TEST`, @"teSt";
@test @`test` @TEST @`TEST` @"teSt"
1 1 1 1 1
set @TEST=2;
select @test, @`test`, @TEST, @`TEST`, @"teSt";
@test @`test` @TEST @`TEST` @"teSt"
2 2 2 2 2
set @"tEST"=3;
select @test, @`test`, @TEST, @`TEST`, @"teSt";
@test @`test` @TEST @`TEST` @"teSt"
3 3 3 3 3
set @`TeST`=4;
select @test, @`test`, @TEST, @`TEST`, @"teSt";
@test @`test` @TEST @`TEST` @"teSt"
4 4 4 4 4
select @`teST`:=5;
@`teST`:=5
5
select @test, @`test`, @TEST, @`TEST`, @"teSt";
@test @`test` @TEST @`TEST` @"teSt"
5 5 5 5 5
set @select=2,@t5=1.23456;
select @`select`,@not_used;
@`select` @not_used
2 NULL
set @test_int=10,@test_double=1e-10,@test_string="abcdeghi",@test_string2="abcdefghij",@select=NULL;
select @test_int,@test_double,@test_string,@test_string2,@select;
@test_int @test_double @test_string @test_string2 @select
@ -286,6 +308,8 @@ set sql_buffer_result=1;
set sql_log_bin=1;
set sql_log_off=1;
set sql_log_update=1;
Warnings:
Note 1271 The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored.
set sql_low_priority_updates=1;
set sql_max_join_size=200;
select @@sql_max_join_size,@@max_join_size;

View file

@ -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;

145
mysql-test/t/sp-error.test Normal file
View file

@ -0,0 +1,145 @@
#
# Stored PROCEDURE error tests
#
# Make sure we don't have any procedures left.
delete from mysql.proc;
delimiter |;
# This should give three syntax errors (sometimes crashed; bug #643)
# (Unfortunately, this is not a 100% test, on some platforms this
# passed despite the bug.)
--error 1064
create procedure syntaxerror(t int)|
--error 1064
create procedure syntaxerror(t int)|
--error 1064
create procedure syntaxerror(t int)|
# 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 1259
create procedure foo()
create procedure bar() set @x=3|
--error 1259
create procedure foo()
create function bar() returns double return 2.3|
# Already exists
--error 1260
create procedure proc1()
set @x = 42|
--error 1260
create function func1() returns int
return 42|
drop procedure proc1|
drop function func1|
# Does not exist
--error 1261
alter procedure foo|
--error 1261
alter function foo|
--error 1261
drop procedure foo|
--error 1261
drop function foo|
--error 1261
call foo()|
drop procedure if exists foo|
# LEAVE/ITERATE with no match
--error 1264
create procedure foo()
foo: loop
leave bar;
end loop|
--error 1264
create procedure foo()
foo: loop
iterate bar;
end loop|
# Redefining label
--error 1265
create procedure foo()
foo: loop
foo: loop
set @x=2;
end loop foo;
end loop foo|
# End label mismatch
--error 1266
create procedure foo()
foo: loop
set @x=2;
end loop bar|
# Referring to undef variable
--error 1267
create procedure foo(out x int)
begin
declare y int;
set x = y;
end|
# We require INTO in SELECTs for some older clients (as mysql and mysqltest,
# for now).
create procedure foo()
begin
select name from mysql.proc;
select type from mysql.proc;
end|
--error 1268
call foo()|
drop procedure foo|
# RETURN in FUNCTION only
--error 1269
create procedure foo()
return 42|
# Doesn't allow queries in FUNCTIONs (for now :-( )
--error 1270
create function foo() returns int
begin
declare x int;
select max(c) into x from test.t;
return x;
end|
# Wrong number of arguments
create procedure p(x int)
insert into test.t1 values (x)|
create function f(x int) returns int
return x+42|
--error 1274
call p()|
--error 1274
call p(1, 2)|
--error 1274
select f()|
--error 1274
select f(1, 2)|
drop procedure p|
drop function f|
delimiter ;|

640
mysql-test/t/sp.test Normal file
View file

@ -0,0 +1,640 @@
#
# Basic stored PROCEDURE tests
#
#
use test;
--disable_warnings
drop table if exists t1;
drop table if exists t2;
--enable_warnings
create table t1 (
id char(16) not null,
data int not null
);
create table t2 (
s char(16) not null,
i int not null,
d double not null
);
# Single statement, no params.
create procedure foo42()
insert into test.t1 values ("foo", 42);
call foo42();
select * from t1;
delete from t1;
drop procedure foo42;
# USE test: Make sure we remain in the same DB.
create procedure u()
use sptmp;
--disable_warnings
drop database if exists sptmp;
--enable_warnings
create database sptmp;
use test;
call u();
select database();
drop database sptmp;
drop procedure u;
# Single statement, two IN params.
create procedure bar(x char(16), y int)
insert into test.t1 values (x, y);
call bar("bar", 666);
select * from t1;
delete from t1;
# Don't drop procedure yet...
# Now for multiple statements...
delimiter |;
# Two statements.
create procedure two(x1 char(16), x2 char(16), y int)
begin
insert into test.t1 values (x1, y);
insert into test.t1 values (x2, y);
end|
call two("one", "two", 3)|
select * from t1|
delete from t1|
drop procedure two|
# Simple test of local variables and SET.
create procedure locset(x char(16), y int)
begin
declare z1, z2 int;
set z1 = y;
set z2 = z1+2;
insert into test.t1 values (x, z2);
end|
call locset("locset", 19)|
select * from t1|
delete from t1|
drop procedure locset|
# The peculiar (non-standard) mixture of variables types in SET.
create procedure mixset(x char(16), y int)
begin
declare z int;
set @z = y, z = 666, max_join_size = 100;
insert into test.t1 values (x, z);
end|
call mixset("mixset", 19)|
show variables like 'max_join_size'|
select id,data,@z from t1|
delete from t1|
drop procedure mixset|
# Multiple CALL statements, one with OUT parameter.
create procedure zip(x char(16), y int)
begin
declare z int;
call zap(y, z);
call bar(x, z);
end|
# SET local variables and OUT parameter.
create procedure zap(x int, out y int)
begin
declare z int;
set z = x+1, y = z;
end|
call zip("zip", 99)|
select * from t1|
delete from t1|
drop procedure zip|
drop procedure zap|
drop procedure bar|
# "Deep" calls...
create procedure c1(x int)
call c2("c", x)|
create procedure c2(s char(16), x int)
call c3(x, s)|
create procedure c3(x int, s char(16))
call c4("level", x, s)|
create procedure c4(l char(8), x int, s char(16))
insert into t1 values (concat(l,s), x)|
call c1(42)|
select * from t1|
delete from t1|
drop procedure c1|
drop procedure c2|
drop procedure c3|
drop procedure c4|
# INOUT test
create procedure iotest(x1 char(16), x2 char(16), y int)
begin
call inc2(x2, y);
insert into test.t1 values (x1, y);
end|
create procedure inc2(x char(16), y int)
begin
call inc(y);
insert into test.t1 values (x, y);
end|
create procedure inc(inout io int)
set io = io + 1|
call iotest("io1", "io2", 1)|
select * from t1|
delete from t1|
drop procedure iotest|
drop procedure inc2|
drop procedure inc|
# Call-by-value test
# The expected result is:
# ("cbv2", 4)
# ("cbv1", 4711)
create procedure cbv1()
begin
declare y int default 3;
call cbv2(y+1, y);
insert into test.t1 values ("cbv1", y);
end|
create procedure cbv2(y1 int, inout y2 int)
begin
set y2 = 4711;
insert into test.t1 values ("cbv2", y1);
end|
call cbv1()|
select * from t1|
delete from t1|
drop procedure cbv1|
drop procedure cbv2|
# Subselect arguments
insert into t2 values ("a", 1, 1.1), ("b", 2, 1.2), ("c", 3, 1.3)|
create procedure sub1(id char(16), x int)
insert into test.t1 values (id, x)|
# QQ This doesn't work yet
#create procedure sub2(id char(16))
#begin
# declare x int;
# set x = (select sum(t.x) from test.t2 t);
# insert into test.t1 values (id, x);
#end|
create function sub3(i int) returns int
return i+1|
call sub1("sub1a", (select 7))|
call sub1("sub1b", (select max(i) from t2))|
call sub1("sub1c", (select i,d from t2 limit 1))|
call sub1("sub1d", (select 1 from (select 1) a))|
#call sub2("sub2");
select * from t1|
select sub3((select max(i) from t2))|
drop procedure sub1|
#drop procedure sub2|
drop function sub3|
# Basic tests of the flow control constructs
# Just test on 'x'...
create procedure a0(x int)
while x do
set x = x-1;
insert into test.t1 values ("a0", x);
end while|
call a0(3)|
select * from t1|
delete from t1|
drop procedure a0|
# The same, but with a more traditional test.
create procedure a(x int)
while x > 0 do
set x = x-1;
insert into test.t1 values ("a", x);
end while|
call a(3)|
select * from t1|
delete from t1|
drop procedure a|
# REPEAT
create procedure b(x int)
repeat
insert into test.t1 values (repeat("b",3), x);
set x = x-1;
until x = 0 end repeat|
call b(3)|
select * from t1|
delete from t1|
drop procedure b|
# Check that repeat isn't parsed the wrong way
create procedure b2(x int)
repeat(select 1 into outfile 'b2');
insert into test.t1 values (repeat("b2",3), x);
set x = x-1;
until x = 0 end repeat|
# We don't actually want to call it.
drop procedure b2|
# Labelled WHILE with ITERATE (pointless really)
create procedure c(x int)
hmm: while x > 0 do
insert into test.t1 values ("c", x);
set x = x-1;
iterate hmm;
insert into test.t1 values ("x", x);
end while hmm|
call c(3)|
select * from t1|
delete from t1|
drop procedure c|
# Labelled WHILE with LEAVE
create procedure d(x int)
hmm: while x > 0 do
insert into test.t1 values ("d", x);
set x = x-1;
leave hmm;
insert into test.t1 values ("x", x);
end while hmm|
call d(3)|
select * from t1|
delete from t1|
drop procedure d|
# LOOP, with simple IF statement
create procedure e(x int)
foo: loop
if x = 0 then
leave foo;
end if;
insert into test.t1 values ("e", x);
set x = x-1;
end loop foo|
call e(3)|
select * from t1|
delete from t1|
drop procedure e|
# A full IF statement
create procedure f(x int)
if x < 0 then
insert into test.t1 values ("f", 0);
elseif x = 0 then
insert into test.t1 values ("f", 1);
else
insert into test.t1 values ("f", 2);
end if|
call f(-2)|
call f(0)|
call f(4)|
select * from t1|
delete from t1|
drop procedure f|
# This form of CASE is really just syntactic sugar for IF-ELSEIF-...
create procedure g(x int)
case
when x < 0 then
insert into test.t1 values ("g", 0);
when x = 0 then
insert into test.t1 values ("g", 1);
else
insert into test.t1 values ("g", 2);
end case|
call g(-42)|
call g(0)|
call g(1)|
select * from t1|
delete from t1|
drop procedure g|
# The "simple CASE"
create procedure h(x int)
case x
when 0 then
insert into test.t1 values ("h0", x);
when 1 then
insert into test.t1 values ("h1", x);
else
insert into test.t1 values ("h?", x);
end case|
call h(0)|
call h(1)|
call h(17)|
select * from t1|
delete from t1|
drop procedure h|
# SELECT INTO local variables
create procedure into_test(x char(16), y int)
begin
insert into test.t1 values (x, y);
select id,data into x,y from test.t1 limit 1;
insert into test.t1 values (concat(x, "2"), y+2);
end|
call into_test("into", 100)|
select * from t1|
delete from t1|
drop procedure into_test|
# SELECT INTO with a mix of local and global variables
create procedure into_test2(x char(16), y int)
begin
insert into test.t1 values (x, y);
select id,data into x,@z from test.t1 limit 1;
insert into test.t1 values (concat(x, "2"), y+2);
end|
call into_test2("into", 100)|
select id,data,@z from t1|
delete from t1|
drop procedure into_test2|
# These two (and the two procedures above) caused an assert() to fail in
# sql_base.cc:lock_tables() at some point.
create procedure into_outfile(x char(16), y int)
begin
insert into test.t1 values (x, y);
select * into outfile "/tmp/spout" from test.t1;
insert into test.t1 values (concat(x, "2"), y+2);
end|
system rm -f /tmp/spout|
call into_outfile("ofile", 1)|
system rm -f /tmp/spout|
delete from t1|
drop procedure into_outfile|
create procedure into_dumpfile(x char(16), y int)
begin
insert into test.t1 values (x, y);
select * into dumpfile "/tmp/spdump" from test.t1 limit 1;
insert into test.t1 values (concat(x, "2"), y+2);
end|
system rm -f /tmp/spdump|
call into_dumpfile("dfile", 1)|
system rm -f /tmp/spdump|
delete from t1|
drop procedure into_dumpfile|
create procedure create_select(x char(16), y int)
begin
insert into test.t1 values (x, y);
create table test.t3 select * from test.t1;
insert into test.t3 values (concat(x, "2"), y+2);
end|
--disable_warnings
drop table if exists t3|
--enable_warnings
call create_select("cs", 90)|
select * from t1, t3|
--disable_warnings
drop table if exists t3|
--enable_warnings
delete from t1|
drop procedure create_select|
# A minimal, constant FUNCTION.
create function e() returns double
return 2.7182818284590452354|
set @e = e()|
select e(), @e|
# A minimal function with one argument
create function inc(i int) returns int
return i+1|
select inc(1), inc(99), inc(-71)|
# A minimal function with two arguments
create function mul(x int, y int) returns int
return x*y|
select mul(1,1), mul(3,5), mul(4711, 666)|
# A minimal string function
create function append(s1 char(8), s2 char(8)) returns char(16)
return concat(s1, s2)|
select append("foo", "bar")|
# A function with flow control
create function fac(n int unsigned) returns bigint unsigned
begin
declare f bigint unsigned default 1;
while n > 1 do
set f = f * n;
set n = n - 1;
end while;
return f;
end|
select fac(1), fac(2), fac(5), fac(10)|
# Nested calls
create function fun(d double, i int, u int unsigned) returns double
return mul(inc(i), fac(u)) / e()|
select fun(2.3, 3, 5)|
# Various function calls in differen statements
insert into t2 values (append("xxx", "yyy"), mul(4,3), e())|
insert into t2 values (append("a", "b"), mul(2,mul(3,4)), fun(1.7, 4, 6))|
# These don't work yet.
select * from t2 where s = append("a", "b")|
select * from t2 where i = mul(4,3) or i = mul(mul(3,4),2)|
select * from t2 where d = e()|
select * from t2|
delete from t2|
drop function e|
drop function inc|
drop function mul|
drop function append|
drop function fun|
#
# Some "real" examples
#
# fac
--disable_warnings
drop table if exists fac|
--enable_warnings
create table fac (n int unsigned not null primary key, f bigint unsigned)|
create procedure ifac(n int unsigned)
begin
declare i int unsigned default 1;
if n > 20 then
set n = 20; # bigint overflow otherwise
end if;
while i <= n do
begin
insert into test.fac values (i, fac(i));
set i = i + 1;
end;
end while;
end|
call ifac(20)|
select * from fac|
drop table fac|
drop procedure ifac|
drop function fac|
# primes
--disable_warnings
drop table if exists primes|
--enable_warnings
create table primes (
i int unsigned not null primary key,
p bigint unsigned not null
)|
insert into primes values
( 0, 3), ( 1, 5), ( 2, 7), ( 3, 11), ( 4, 13),
( 5, 17), ( 6, 19), ( 7, 23), ( 8, 29), ( 9, 31),
(10, 37), (11, 41), (12, 43), (13, 47), (14, 53),
(15, 59), (16, 61), (17, 67), (18, 71), (19, 73),
(20, 79), (21, 83), (22, 89), (23, 97), (24, 101),
(25, 103), (26, 107), (27, 109), (28, 113), (29, 127),
(30, 131), (31, 137), (32, 139), (33, 149), (34, 151),
(35, 157), (36, 163), (37, 167), (38, 173), (39, 179),
(40, 181), (41, 191), (42, 193), (43, 197), (44, 199)|
create procedure opp(n bigint unsigned, out pp bool)
begin
declare r double;
declare b, s bigint unsigned default 0;
set r = sqrt(n);
again:
loop
if s = 45 then
set b = b+200, s = 0;
else
begin
declare p bigint unsigned;
select t.p into p from test.primes t where t.i = s;
if b+p > r then
set pp = 1;
leave again;
end if;
if mod(n, b+p) = 0 then
set pp = 0;
leave again;
end if;
set s = s+1;
end;
end if;
end loop again;
end|
create procedure ip(m int unsigned)
begin
declare p bigint unsigned;
declare i int unsigned;
set i=45, p=201;
while i < m do
begin
declare pp bool default 0;
call opp(p, pp);
if pp then
insert into test.primes values (i, p);
set i = i+1;
end if;
set p = p+2;
end;
end while;
end|
# This isn't the fastest way in the world to compute prime numbers, so
# don't be too ambitious. ;-)
call ip(200)|
# We don't want to select the entire table here, just pick a few
# examples.
select * from primes where i=45 or i=100 or i=199|
drop table primes|
drop procedure opp|
drop procedure ip|
delimiter ;|
drop table t1;
drop table t2;

View file

@ -351,7 +351,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;
-- error 1054
INSERT DELAYED INTO t1 (x) VALUES ((SELECT SUM(x) FROM t2));
@ -503,6 +502,9 @@ select ROW(1, 1, 'a') IN (select b,a,c from t1 where c='b' or c='a');
select ROW(1, 1, 'a') IN (select b,a,c from t1 limit 2);
drop table t1;
#
# DO & SET
#
create table t1 (a int);
insert into t1 values (1);
do @a:=(SELECT a from t1);
@ -516,6 +518,7 @@ do (SELECT a from t1);
-- error 1146
set @a:=(SELECT a from t1);
CREATE TABLE t1 (a int, KEY(a));
HANDLER t1 OPEN;
-- error 1149

View file

@ -5,8 +5,20 @@
drop table if exists t1,t2;
--enable_warnings
set @`test`=1,@TEST=3,@select=2,@t5=1.23456;
select @test,@`select`,@TEST,@not_used;
# case insensitivity tests (new in 5.0)
set @`test`=1;
select @test, @`test`, @TEST, @`TEST`, @"teSt";
set @TEST=2;
select @test, @`test`, @TEST, @`TEST`, @"teSt";
set @"tEST"=3;
select @test, @`test`, @TEST, @`TEST`, @"teSt";
set @`TeST`=4;
select @test, @`test`, @TEST, @`TEST`, @"teSt";
select @`teST`:=5;
select @test, @`test`, @TEST, @`TEST`, @"teSt";
set @select=2,@t5=1.23456;
select @`select`,@not_used;
set @test_int=10,@test_double=1e-10,@test_string="abcdeghi",@test_string2="abcdefghij",@select=NULL;
select @test_int,@test_double,@test_string,@test_string2,@select;
set @test_int="hello",@test_double="hello",@test_string="hello",@test_string2="hello";

View file

@ -29,7 +29,7 @@ rm -rf Makefile.in.bk
make clean bin-dist
# mark the build
for file in *.tar.gz
for file in *.tar.gz *.zip
do
if (expr "$file" : "mysql-[1-9].*" > /dev/null)
then

View file

@ -8,6 +8,7 @@ set -e
path=`dirname $0`
$path/compile-netware-src
$path/compile-netware-standard
$path/compile-netware-debug
#$path/compile-netware-max

View file

@ -0,0 +1,36 @@
#! /bin/sh
# debug
#set -x
# stop on errors
set -e
if test ! -r ./sql/mysqld.cc
then
echo "you must start from the top source directory"
exit 1
fi
path=`dirname $0`
# clean
if test -e "Makefile"; then
make -k clean;
make -k distclean;
fi
# remove other files
rm -f NEW-RPMS/*
rm -f */.deps/*.P
rm -rf Makefile.in.bk
# zip source
files=`pwd | sed -e "s/.*\\\(mysql-.*\)/\1/"`
file=`pwd | sed -e "s/.*\\mysql-\(.*\)/mysql-src-\1-pc-netware-i686/"`
cd ..
if test -e "$file.zip"; then rm -f $file.zip; fi
zip -r $file.zip $files -x \*.zip -x \*.tar.gz
if test -e "./$files/$file.zip"; then mv -f ./$files/$file.zip ./$files/$file.zip.old; fi
mv -f $file.zip ./$files/$file.zip

View file

@ -13,7 +13,7 @@ path=`dirname $0`
suffix="standard"
extra_configs=" \
--with-innodb
--with-innodb \
"
. $path/compile-netware-END

View file

@ -0,0 +1,2 @@
kYieldIfTimeSliceUp

View file

@ -7,8 +7,8 @@
export MYDEV="WINE_BUILD_DIR"
export MWCNWx86Includes="$MYDEV/libc/include;$MYDEV/zlib-1.1.4"
export MWNWx86Libraries="$MYDEV/libc/imports;$MYDEV/mw/lib;$MYDEV/zlib-1.1.4"
export MWNWx86LibraryFiles="libcpre.o;libc.imp;netware.imp;mwcrtl.lib;mwcpp.lib;libz.a"
export MWNWx86Libraries="$MYDEV/libc/imports;$MYDEV/mw/lib;$MYDEV/mysql-VERSION/netware/BUILD;$MYDEV/zlib-1.1.4"
export MWNWx86LibraryFiles="libcpre.o;libc.imp;netware.imp;mwcrtl.lib;mwcpp.lib;knetware.imp;libz.a"
export WINEPATH="$MYDEV/mw/bin"
@ -19,9 +19,9 @@ export AR='mwldnlm'
export AR_FLAGS='-type library -o'
export AS='mwasmnlm'
export CC='mwccnlm -gccincludes'
export CFLAGS='-dialect c -proc 686 -relax_pointers'
export CFLAGS='-align 8 -proc 686 -relax_pointers -dialect c'
export CXX='mwccnlm -gccincludes'
export CXXFLAGS='-dialect c++ -proc 686 -bool on -wchar_t on -relax_pointers -D_WCHAR_T'
export CXXFLAGS='-align 8 -proc 686 -relax_pointers -dialect c++ -bool on -wchar_t on -D_WCHAR_T'
export LD='mwldnlm'
export LDFLAGS='-entry _LibCPrelude -exit _LibCPostlude -flags pseudopreemption'
export RANLIB=:

View file

@ -147,10 +147,12 @@ then
fi
# make files writeable
echo "making files writable..."
cd $target_dir
chmod -R u+rw,g+rw .
# edit the mvenv file
echo "updating the mwenv environment file..."
mwenv="./netware/BUILD/mwenv"
mv -f $mwenv $mwenv.org
sed -e "s;WINE_BUILD_DIR;$wine_build_dir;g" \
@ -158,6 +160,17 @@ sed -e "s;WINE_BUILD_DIR;$wine_build_dir;g" \
-e "s;VERSION;$version;g" $mwenv.org > $mwenv
chmod +rwx $mwenv
#edit the def file versions
echo "updating *.def file versions..."
nlm_version=`echo "$version" | sed -e "s;\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*;\1, \2, \3;"`
for file in ./netware/*.def
do
mv -f $file $file.org
sed -e "s;VERSION.*;VERSION $nlm_version;g" $file.org > $file
rm $file.org
done
# build linux tools
echo "compiling linux tools..."
./netware/BUILD/compile-linux-tools

View file

@ -14,35 +14,34 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
INCLUDES = -I$(srcdir)/../include -I../include -I..
bin_PROGRAMS = mysqld_safe mysql_install_db mysql_test_run libmysql
mysqld_safe_SOURCES= mysqld_safe.c my_manage.c
INCLUDES= -I$(srcdir)/../include -I../include -I..
bin_PROGRAMS= mysqld_safe mysql_install_db mysql_test_run libmysql
mysqld_safe_SOURCES= mysqld_safe.c my_manage.c
mysql_install_db_SOURCES= mysql_install_db.c my_manage.c
mysql_test_run_SOURCES= mysql_test_run.c my_manage.c
libmysql_SOURCES= libmysqlmain.c
libmysql_LDADD = ../libmysql/.libs/libmysqlclient.a
libmysql_SOURCES= libmysqlmain.c
libmysql_LDADD= ../libmysql/.libs/libmysqlclient.a
netware_build_files = client/mysql.def client/mysqladmin.def \
client/mysqlbinlog.def client/mysqlcheck.def \
client/mysqldump.def client/mysqlimport.def \
client/mysqlshow.def client/mysqltest.def \
extra/mysql_install.def extra/my_print_defaults.def \
extra/perror.def extra/replace.def \
extra/resolveip.def extra/comp_err.def \
isam/isamchk.def \
isam/isamlog.def isam/pack_isam.def \
libmysqld/libmysqld.def myisam/myisamchk.def \
myisam/myisamlog.def myisam/myisampack.def \
sql/mysqld.def
netware_build_files = client/mysql.def client/mysqladmin.def \
client/mysqlbinlog.def client/mysqlcheck.def \
client/mysqldump.def client/mysqlimport.def \
client/mysqlshow.def client/mysqltest.def \
extra/mysql_install.def extra/my_print_defaults.def \
extra/perror.def extra/replace.def \
extra/resolveip.def extra/comp_err.def \
isam/isamchk.def \
isam/isamlog.def isam/pack_isam.def \
libmysqld/libmysqld.def myisam/myisamchk.def \
myisam/myisamlog.def myisam/myisampack.def \
sql/mysqld.def
link_sources:
set -x; \
for f in $(netware_build_files); do \
rm -f $(srcdir)/../$$f; \
org=`echo $$f | sed -e 's/.*\/\(.*\)/\1/g'`; \
@LN_CP_F@ $(srcdir)/$$org $(srcdir)/../$$f; \
rm -f $(srcdir)/../$$f; \
org=`echo $$f | sed -e 's/.*\/\(.*\)/\1/g'`; \
@LN_CP_F@ $(srcdir)/$$org $(srcdir)/../$$f; \
done;
# Don't update the files from bitkeeper
%::SCCS/s.%

View file

@ -266,6 +266,7 @@ void start_master()
int err, i;
char master_out[PATH_MAX];
char master_err[PATH_MAX];
char temp[PATH_MAX];
// remove old berkeley db log files that can confuse the server
removef("%s/log.*", master_dir);
@ -289,6 +290,20 @@ void start_master()
if (master_init_script[0] != NULL)
{
// run_init_script(master_init_script);
// TODO: use the scripts
if (strindex(master_init_script, "repair_part2-master.sh") != NULL)
{
FILE *fp;
// create an empty index file
snprintf(temp, PATH_MAX, "%s/test/t1.MYI", master_dir);
fp = fopen(temp, "wb+");
fputs("1", fp);
fclose(fp);
}
}
// redirection files

View file

@ -73,9 +73,25 @@ if [ $BASE_SYSTEM != "netware" ] ; then
chmod o-rwx $BASE/data $BASE/data/*
fi
for i in ChangeLog COPYING COPYING.LIB README Docs/INSTALL-BINARY \
MySQLEULA.txt Docs/manual.html Docs/manual.txt Docs/manual_toc.html \
LICENSE.doc README.NW Docs/mysqlbug.txt
# Non platform-specific doc files:
DOC_FILES=" \
ChangeLog COPYING COPYING.LIB README \
Docs/manual.html Docs/manual.txt Docs/manual_toc.html \
Docs/mysqlbug.txt \
";
# Platform-specific doc files:
if [ $BASE_SYSTEM = "netware" ] ; then
DOC_FILES="$DOC_FILES \
";
# For all other platforms:
else
DOC_FILES="$DOC_FILES \
Docs/INSTALL-BINARY MySQLEULA.txt \
";
fi
for i in $DOC_FILES
do
if [ -f $i ]
then
@ -83,7 +99,7 @@ do
fi
done
# Non platform-specific bin dir files:
# Non platform-specific bin files:
BIN_FILES="extra/comp_err$BS extra/replace$BS extra/perror$BS \
extra/resolveip$BS extra/my_print_defaults$BS \
extra/resolve_stack_dump$BS extra/mysql_waitpid$BS \
@ -93,18 +109,18 @@ BIN_FILES="extra/comp_err$BS extra/replace$BS extra/perror$BS \
client/mysql$BS client/mysqlshow$BS client/mysqladmin$BS \
client/mysqldump$BS client/mysqlimport$BS \
client/mysqltest$BS client/mysqlcheck$BS \
client/mysqlbinlog$BS
client/mysqlbinlog$BS \
";
# Platform-specific bin dir files:
# Platform-specific bin files:
if [ $BASE_SYSTEM = "netware" ] ; then
BIN_FILES="$BIN_FILES \
netware/mysqld_safe$BS netware/mysql_install_db$BS \
netware/init_db.sql netware/test_db.sql netware/mysql_explain_log$BS \
netware/mysqlhotcopy$BS netware/libmysql$BS netware/init_secure_db.sql
netware/mysqlhotcopy$BS netware/libmysql$BS netware/init_secure_db.sql \
";
# For all other platforms:
else
# For all other platforms:
BIN_FILES="$BIN_FILES \
client/mysqlmanagerc \
client/mysqlmanager-pwgen tools/mysqlmanager \
@ -224,7 +240,9 @@ rm -f $BASE/bin/Makefile* $BASE/bin/*.in $BASE/bin/*.sh $BASE/bin/mysql_install_
# Make safe_mysqld a symlink to mysqld_safe for backwards portability
# To be removed in MySQL 4.1
(cd $BASE/bin ; ln -s mysqld_safe safe_mysqld )
if [ $BASE_SYSTEM != "netware" ] ; then
(cd $BASE/bin ; ln -s mysqld_safe safe_mysqld )
fi
# Clean up if we did this from a bk tree
if [ -d $BASE/sql-bench/SCCS ] ; then
@ -283,29 +301,48 @@ which_1 ()
exit 1
}
#
# Create the result tar file
#
tar=`which_1 gnutar gtar`
if test "$?" = "1" -o "$tar" = ""
then
tar=tar
fi
echo "Using $tar to create archive"
cd $TMP
if [ $BASE_SYSTEM = "netware" ] ; then
#
# Create a zip file for NetWare users
#
if test -e "$SOURCE/$NEW_NAME.zip"; then rm $SOURCE/$NEW_NAME.zip; fi
zip -r $SOURCE/$NEW_NAME.zip $NEW_NAME
echo "$NEW_NAME.zip created"
else
#
# Create the result tar file
#
tar=`which_1 gnutar gtar`
if test "$?" = "1" -o "$tar" = ""
then
tar=tar
fi
echo "Using $tar to create archive"
OPT=cvf
if [ x$SILENT = x1 ] ; then
OPT=cf
fi
$tar $OPT $SOURCE/$NEW_NAME.tar $NEW_NAME
cd $SOURCE
echo "Compressing archive"
gzip -9 $NEW_NAME.tar
echo "$NEW_NAME.tar.gz created"
OPT=cvf
if [ x$SILENT = x1 ] ; then
OPT=cf
fi
$tar $OPT $SOURCE/$NEW_NAME.tar $NEW_NAME
cd $SOURCE
echo "Compressing archive"
gzip -9 $NEW_NAME.tar
echo "Removing temporary directory"
rm -r -f $BASE
echo "$NEW_NAME.tar.gz created"

View file

@ -58,6 +58,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
log_event.h sql_repl.h slave.h \
stacktrace.h sql_sort.h sql_cache.h set_var.h \
spatial.h gstream.h client_settings.h
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.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 \
@ -86,7 +87,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
slave.cc sql_repl.cc sql_union.cc sql_derived.cc \
client.c sql_client.cc mini_client_errors.c pack.c\
stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)

View file

@ -331,7 +331,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
byte *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
my_off_t record;
TABLE *sort_form;
volatile bool *killed= &current_thd->killed;
volatile THD::killed_state *killed= &current_thd->killed;
handler *file;
DBUG_ENTER("find_all_keys");
DBUG_PRINT("info",("using: %s",(select?select->quick?"ranges":"where":"every row")));
@ -775,15 +775,15 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
BUFFPEK *buffpek,**refpek;
QUEUE queue;
qsort2_cmp cmp;
volatile bool *killed= &current_thd->killed;
bool not_killable;
volatile THD::killed_state *killed= &current_thd->killed;
THD::killed_state not_killable;
DBUG_ENTER("merge_buffers");
statistic_increment(filesort_merge_passes, &LOCK_status);
if (param->not_killable)
{
killed= &not_killable;
not_killable= 0;
not_killable=THD::NOT_KILLED;
}
error=0;
@ -1129,7 +1129,7 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
The fact is the filter 'field->query_id != thd->query_id'
doesn't work for alter table
*/
if (thd->lex.sql_command != SQLCOM_SELECT)
if (thd->lex->sql_command != SQLCOM_SELECT)
return 0;
for (pfield= ptabfield; (field= *pfield) ; pfield++)
{

View file

@ -2103,7 +2103,7 @@ static void print_msg(THD *thd, const char *table_name, const char *op_name,
protocol->store(msg_type);
protocol->store(msgbuf);
if (protocol->write())
thd->killed=1;
thd->killed=THD::KILL_CONNECTION;
}
#endif

View file

@ -2021,8 +2021,8 @@ ha_innobase::write_row(
skip_auto_inc_decr = FALSE;
if (error == DB_DUPLICATE_KEY
&& (user_thd->lex.sql_command == SQLCOM_REPLACE
|| user_thd->lex.sql_command
&& (user_thd->lex->sql_command == SQLCOM_REPLACE
|| user_thd->lex->sql_command
== SQLCOM_REPLACE_SELECT)) {
skip_auto_inc_decr= TRUE;

View file

@ -89,9 +89,9 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
extern "C" {
volatile bool *killed_ptr(MI_CHECK *param)
int *killed_ptr(void *thd)
{
return &(((THD *)(param->thd))->killed);
return (int*)&((THD *)thd)->killed;
}
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
@ -388,7 +388,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
{
HA_CHECK_OPT tmp_check_opt;
char* backup_dir = thd->lex.backup_dir;
char* backup_dir = thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name;
int error;
@ -428,7 +428,7 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
{
char* backup_dir = thd->lex.backup_dir;
char* backup_dir = thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name;
int error;

View file

@ -22,6 +22,7 @@
#include "mysql_priv.h"
#include <m_ctype.h>
#include "my_dir.h"
#include "sp_rcontext.h"
static void mark_as_dependent(bool outer_resolving,
SELECT_LEX *last, SELECT_LEX_NODE *current,
@ -193,6 +194,23 @@ CHARSET_INFO * Item::default_charset() const
return current_thd->variables.collation_connection;
}
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);
}
bool DTCollation::aggregate(DTCollation &dt)
{
if (!my_charset_same(collation, dt.collation))
@ -854,7 +872,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
Item **refer= (Item **)not_found_item;
uint counter;
// Prevent using outer fields in subselects, that is not supported now
SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select;
SELECT_LEX *cursel=(SELECT_LEX *) thd->lex->current_select;
if (outer_resolving ||
cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE)
for (SELECT_LEX *sl=(outer_resolving?cursel:cursel->outer_select());
@ -1316,8 +1334,8 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
TABLE_LIST *where= 0, *table_list;
SELECT_LEX *sl= (outer_resolving?
thd->lex.current_select->select_lex():
thd->lex.current_select->outer_select());
thd->lex->current_select->select_lex():
thd->lex->current_select->outer_select());
/*
Finding only in current select will be performed for selects that have
not outer one and for derived tables (which not support using outer
@ -1325,10 +1343,10 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
*/
if (outer_resolving ||
(ref= find_item_in_list(this,
*(thd->lex.current_select->get_item_list()),
*(thd->lex->current_select->get_item_list()),
&counter,
((sl &&
thd->lex.current_select->master_unit()->
thd->lex->current_select->master_unit()->
first_select()->linkage !=
DERIVED_TABLE_TYPE) ?
REPORT_EXCEPT_NOT_FOUND :
@ -1376,7 +1394,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
// Call to report error
find_item_in_list(this,
*(thd->lex.current_select->get_item_list()),
*(thd->lex->current_select->get_item_list()),
&counter,
REPORT_ALL_ERRORS);
ref= 0;
@ -1388,7 +1406,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
Item_field* fld;
if (!((*reference)= fld= new Item_field(tmp)))
return 1;
mark_as_dependent(outer_resolving, last, thd->lex.current_select, fld);
mark_as_dependent(outer_resolving, last, thd->lex->current_select, fld);
return 0;
}
else
@ -1399,7 +1417,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
"forward reference in item list");
return -1;
}
mark_as_dependent(outer_resolving, last, thd->lex.current_select,
mark_as_dependent(outer_resolving, last, thd->lex->current_select,
this);
ref= last->ref_pointer_array + counter;
}
@ -1414,7 +1432,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
"forward reference in item list");
return -1;
}
ref= thd->lex.current_select->ref_pointer_array + counter;
ref= thd->lex->current_select->ref_pointer_array + counter;
}
}
@ -1429,8 +1447,8 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
if (((*ref)->with_sum_func && name &&
(depended_from ||
!(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE &&
thd->lex.current_select->select_lex()->having_fix_field))) ||
!(thd->lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
thd->lex->current_select->select_lex()->having_fix_field))) ||
!(*ref)->fixed)
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,

View file

@ -186,6 +186,8 @@ public:
collation.derivation= collation_arg->derivation;
}
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; }
@ -199,6 +201,57 @@ public:
};
// 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
{

View file

@ -83,7 +83,7 @@ Item *create_func_ceiling(Item* a)
Item *create_func_connection_id(void)
{
THD *thd=current_thd;
thd->lex.safe_to_cache_query=0;
thd->lex->safe_to_cache_query=0;
return new Item_int(NullS,(longlong)
((thd->slave_thread) ?
thd->variables.pseudo_thread_id :
@ -163,7 +163,7 @@ Item *create_func_floor(Item* a)
Item *create_func_found_rows(void)
{
THD *thd=current_thd;
thd->lex.safe_to_cache_query=0;
thd->lex->safe_to_cache_query=0;
return new Item_int(NullS,(longlong) thd->found_rows(),21);
}
@ -174,7 +174,7 @@ Item *create_func_from_days(Item* a)
Item *create_func_get_lock(Item* a, Item *b)
{
current_thd->lex.uncacheable();
current_thd->lex->uncacheable();
return new Item_func_get_lock(a, b);
}
@ -344,7 +344,7 @@ Item *create_func_radians(Item *a)
Item *create_func_release_lock(Item* a)
{
current_thd->lex.uncacheable();
current_thd->lex->uncacheable();
return new Item_func_release_lock(a);
}
@ -465,7 +465,7 @@ Item *create_func_year(Item* a)
Item *create_load_file(Item* a)
{
current_thd->lex.uncacheable();
current_thd->lex->uncacheable();
return new Item_load_file(a);
}
@ -491,13 +491,13 @@ Item *create_func_cast(Item *a, Item_cast cast_type, CHARSET_INFO *cs)
Item *create_func_is_free_lock(Item* a)
{
current_thd->lex.uncacheable();
current_thd->lex->uncacheable();
return new Item_func_is_free_lock(a);
}
Item *create_func_is_used_lock(Item* a)
{
current_thd->lex.uncacheable();
current_thd->lex->uncacheable();
return new Item_func_is_used_lock(a);
}

View file

@ -31,6 +31,10 @@
#include <zlib.h>
#endif
#include "sp_head.h"
#include "sp_rcontext.h"
#include "sp.h"
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname)
{
my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
@ -2334,7 +2338,7 @@ void Item_func_get_user_var::fix_length_and_dec()
if ((var_entry= get_variable(&thd->user_vars, name, 0)))
{
if (opt_bin_log && is_update_query(thd->lex.sql_command) &&
if (opt_bin_log && is_update_query(thd->lex->sql_command) &&
var_entry->used_query_id != thd->query_id)
{
uint size;
@ -2710,7 +2714,7 @@ Item *get_system_var(enum_var_type var_type, LEX_STRING name)
return 0;
if (!(item=var->item(thd, var_type)))
return 0; // Impossible
thd->lex.uncacheable();
thd->lex->uncacheable();
buff[0]='@';
buff[1]='@';
pos=buff+2;
@ -2736,7 +2740,7 @@ Item *get_system_var(enum_var_type var_type, const char *var_name, uint length,
DBUG_ASSERT(var != 0);
if (!(item=var->item(thd, var_type)))
return 0; // Impossible
thd->lex.uncacheable();
thd->lex->uncacheable();
item->set_name(item_name, 0, system_charset_info); // Will use original name
return item;
}
@ -2797,3 +2801,74 @@ longlong Item_func_is_used_lock::val_int()
null_value=0;
return ull->thread_id;
}
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;
}

View file

@ -1089,3 +1089,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();
};

View file

@ -186,7 +186,7 @@ void Item_singlerow_subselect::select_transformer(THD *thd,
{
have_to_be_excluded= 1;
if (thd->lex.describe)
if (thd->lex->describe)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
@ -576,7 +576,7 @@ void Item_in_subselect::single_value_transformer(THD *thd,
item= (*func)(left_expr, item);
substitution= item;
have_to_be_excluded= 1;
if (thd->lex.describe)
if (thd->lex->describe)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_SELECT_REDUCED), sl->select_number);
@ -719,8 +719,8 @@ int subselect_single_select_engine::prepare()
if (prepared)
return 0;
prepared= 1;
SELECT_LEX_NODE *save_select= thd->lex.current_select;
thd->lex.current_select= select_lex;
SELECT_LEX_NODE *save_select= thd->lex->current_select;
thd->lex->current_select= select_lex;
if (join->prepare(&select_lex->ref_pointer_array,
(TABLE_LIST*) select_lex->table_list.first,
select_lex->with_wild,
@ -733,7 +733,7 @@ int subselect_single_select_engine::prepare()
(ORDER*) 0, select_lex,
select_lex->master_unit(), 0))
return 1;
thd->lex.current_select= save_select;
thd->lex->current_select= save_select;
return 0;
}

View file

@ -57,7 +57,7 @@ Item_sum::Item_sum(THD *thd, Item_sum &item):
void Item_sum::mark_as_sum_func()
{
current_thd->lex.current_select->with_sum_func= 1;
current_thd->lex->current_select->with_sum_func= 1;
with_sum_func= 1;
}

View file

@ -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},
@ -102,6 +104,7 @@ static SYMBOL symbols[] = {
{ "COMMITTED", SYM(COMMITTED_SYM),0,0},
{ "COMPRESSED", SYM(COMPRESSED_SYM),0,0},
{ "CONCURRENT", SYM(CONCURRENT),0,0},
{ "CONNECTION", SYM(CONNECTION_SYM),0,0},
{ "CONSTRAINT", SYM(CONSTRAINT),0,0},
{ "CREATE", SYM(CREATE),0,0},
{ "CROSS", SYM(CROSS),0,0},
@ -109,6 +112,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 +124,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 +147,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 +178,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 +204,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 +223,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},
{ "LEAVES", SYM(LEAVES),0,0},
{ "LEFT", SYM(LEFT),0,0},
{ "LEVEL", SYM(LEVEL_SYM),0,0},
@ -237,6 +247,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},
@ -291,6 +302,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},
@ -321,13 +333,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 */
@ -339,6 +353,7 @@ static SYMBOL symbols[] = {
{ "SECOND", SYM(SECOND_SYM),0,0},
{ "SEPARATOR", SYM(SEPARATOR_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},
@ -353,6 +368,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},
@ -395,6 +411,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},
{ "USER", SYM(USER),0,0},
@ -414,6 +431,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},
{ "NO_WRITE_TO_BINLOG", SYM(NO_WRITE_TO_BINLOG),0,0},
{ "XOR", SYM(XOR),0,0},
{ "X509", SYM(X509_SYM),0,0},
@ -598,7 +616,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)},

View file

@ -154,7 +154,7 @@ retry:
thd->proc_info=0;
if (thd->killed)
{
my_error(ER_SERVER_SHUTDOWN,MYF(0));
thd->send_kill_message();
if (sql_lock)
{
mysql_unlock_tables(thd,sql_lock);

View file

@ -30,7 +30,7 @@
#include <stdarg.h>
#include <m_ctype.h> // For test_if_number
MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
MYSQL_LOG mysql_log, mysql_slow_log, mysql_bin_log;
extern I_List<i_string> binlog_do_db, binlog_ignore_db;
static bool test_if_number(const char *str,
@ -1060,7 +1060,7 @@ err:
/*
Write to normal (not rotable) log
This is the format for the 'normal', 'slow' and 'update' logs.
This is the format for the 'normal' log.
*/
bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
@ -1497,8 +1497,7 @@ err:
/*
Write update log in a format suitable for incremental backup
This is also used by the slow query log.
Write to the slow query log.
*/
bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
@ -1514,12 +1513,6 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
int tmp_errno=0;
char buff[80],*end;
end=buff;
if (!(thd->options & OPTION_UPDATE_LOG) &&
(thd->master_access & SUPER_ACL))
{
VOID(pthread_mutex_unlock(&LOCK_log));
return 0;
}
if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start_arg)
{
current_time=time(NULL);

View file

@ -791,7 +791,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans),
data_buf(0), query(query_arg),
db(thd_arg->db), q_len((uint32) query_length),
error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno),
error_code(thd_arg->killed != THD::NOT_KILLED ? thd->killed_errno() : thd_arg->net.last_errno),
thread_id(thd_arg->thread_id)
{
time_t end_time;

View file

@ -49,7 +49,6 @@ char *sql_strmake_with_convert(const char *str, uint32 arg_length,
CHARSET_INFO *from_cs,
uint32 max_res_length,
CHARSET_INFO *to_cs, uint32 *result_length);
void kill_one_thread(THD *thd, ulong id);
bool net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
@ -358,7 +357,7 @@ bool is_update_query(enum enum_sql_command command);
void free_items(Item *item);
bool alloc_query(THD *thd, char *packet, ulong packet_length);
void mysql_init_select(LEX *lex);
void mysql_init_query(THD *thd);
void mysql_init_query(THD *thd, bool lexonly=0);
bool mysql_new_select(LEX *lex, bool move_down);
void create_select_for_variable(const char *var_name);
void mysql_init_multi_delete(LEX *lex);
@ -369,7 +368,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);
@ -914,22 +913,22 @@ bool flush_error_log(void);
inline bool add_item_to_list(THD *thd, Item *item)
{
return thd->lex.current_select->add_item_to_list(thd, item);
return thd->lex->current_select->add_item_to_list(thd, item);
}
inline bool add_value_to_list(THD *thd, Item *value)
{
return thd->lex.value_list.push_back(value);
return thd->lex->value_list.push_back(value);
}
inline bool add_order_to_list(THD *thd, Item *item, bool asc)
{
return thd->lex.current_select->add_order_to_list(thd, item, asc);
return thd->lex->current_select->add_order_to_list(thd, item, asc);
}
inline bool add_group_to_list(THD *thd, Item *item, bool asc)
{
return thd->lex.current_select->add_group_to_list(thd, item, asc);
return thd->lex->current_select->add_group_to_list(thd, item, asc);
}
inline void mark_as_null_row(TABLE *table)

View file

@ -22,6 +22,7 @@
#include "sql_repl.h"
#include "repl_failsafe.h"
#include "stacktrace.h"
#include "mysys_err.h"
#ifdef HAVE_BERKELEY_DB
#include "ha_berkeley.h"
#endif
@ -254,16 +255,6 @@ my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0;
my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam;
my_bool opt_readonly, use_temp_pool, relay_log_purge;
volatile bool mqh_used = 0;
uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
uint delay_key_write_options, protocol_version;
uint volatile thread_count, thread_running, kill_cached_threads, wake_thread;
ulong back_log, connect_timeout, concurrency;
ulong server_id, thd_startup_options;
ulong table_cache_size, thread_stack, thread_stack_min, what_to_log;
ulong query_buff_size, slow_launch_time, slave_open_temp_tables;
ulong open_files_limit, max_binlog_size;
ulong slave_net_timeout;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0;
@ -579,7 +570,7 @@ static void close_connections(void)
{
DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
tmp->thread_id));
tmp->killed=1;
tmp->killed= THD::KILL_CONNECTION;
if (tmp->mysys_var)
{
tmp->mysys_var->abort=1;
@ -762,6 +753,7 @@ static void __cdecl kill_server(int sig_ptr)
unireg_abort(1); /* purecov: inspected */
else
unireg_end();
#ifdef __NETWARE__
pthread_join(select_thread, NULL); // wait for main thread
#endif /* __NETWARE__ */
@ -854,7 +846,6 @@ void clean_up(bool print_message)
mysql_log.cleanup();
mysql_slow_log.cleanup();
mysql_update_log.cleanup();
mysql_bin_log.cleanup();
#ifdef HAVE_REPLICATION
@ -1213,12 +1204,12 @@ static void server_init(void)
void yyerror(const char *s)
{
THD *thd=current_thd;
char *yytext=(char*) thd->lex.tok_start;
char *yytext=(char*) thd->lex->tok_start;
/* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
s=ER(ER_SYNTAX_ERROR);
net_printf(thd,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "",
thd->lex.yylineno);
thd->lex->yylineno);
}
@ -1345,7 +1336,7 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused)))
THD *thd=current_thd;
DBUG_ENTER("abort_thread");
if (thd)
thd->killed=1;
thd->killed= THD::KILL_CONNECTION;
DBUG_VOID_RETURN;
}
#endif
@ -2145,9 +2136,55 @@ static int init_server_components()
LOG_NORMAL);
if (opt_update_log)
{
open_log(&mysql_update_log, glob_hostname, opt_update_logname, "",
NullS, LOG_NEW);
using_update_log=1;
/*
Update log is removed since 5.0. But we still accept the option.
The idea is if the user already uses the binlog and the update log,
we completely ignore any option/variable related to the update log, like
if the update log did not exist. But if the user uses only the update log,
then we translate everything into binlog for him (with warnings).
Implementation of the above :
- If mysqld is started with --log-update and --log-bin,
ignore --log-update (print a warning), push a warning when SQL_LOG_UPDATE
is used, and turn off --sql-bin-update-same.
This will completely ignore SQL_LOG_UPDATE
- If mysqld is started with --log-update only,
change it to --log-bin (with the filename passed to log-update,
plus '-bin') (print a warning), push a warning when SQL_LOG_UPDATE is
used, and turn on --sql-bin-update-same.
This will translate SQL_LOG_UPDATE to SQL_LOG_BIN.
Note that we tell the user that --sql-bin-update-same is deprecated and
does nothing, and we don't take into account if he used this option or
not; but internally we give this variable a value to have the behaviour we
want (i.e. have SQL_LOG_UPDATE influence SQL_LOG_BIN or not).
As sql-bin-update-same, log-update and log-bin cannot be changed by the user
after starting the server (they are not variables), the user will not
later interfere with the settings we do here.
*/
if (opt_bin_log)
{
opt_sql_bin_update= 0;
sql_print_error("The update log is no longer supported by MySQL in \
version 5.0 and above. It is replaced by the binary log.");
}
else
{
opt_sql_bin_update= 1;
opt_bin_log= 1;
if (opt_update_logname)
{
// as opt_bin_log==0, no need to free opt_bin_logname
if (!(opt_bin_logname= my_strdup(opt_update_logname, MYF(MY_WME))))
exit(EXIT_OUT_OF_MEMORY);
sql_print_error("The update log is no longer supported by MySQL in \
version 5.0 and above. It is replaced by the binary log. Now starting MySQL \
with --log-bin='%s' instead.",opt_bin_logname);
}
else
sql_print_error("The update log is no longer supported by MySQL in \
version 5.0 and above. It is replaced by the binary log. Now starting MySQL \
with --log-bin instead.");
}
}
if (opt_slow_log)
open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
@ -2798,7 +2835,7 @@ static void create_new_thread(THD *thd)
("Can't create thread to handle request (error %d)",
error));
thread_count--;
thd->killed=1; // Safety
thd->killed= THD::KILL_CONNECTION; // Safety
(void) pthread_mutex_unlock(&LOCK_thread_count);
net_printf(thd,ER_CANT_CREATE_THREAD,error);
(void) pthread_mutex_lock(&LOCK_thread_count);
@ -3662,7 +3699,8 @@ Disable with --skip-bdb (will save memory).",
(gptr*) &myisam_log_filename, (gptr*) &myisam_log_filename, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-update", OPT_UPDATE_LOG,
"Log updates to file.# where # is a unique number if not given.",
"The update log is deprecated since version 5.0, is replaced by the binary \
log and this option justs turns on --log-bin instead.",
(gptr*) &opt_update_logname, (gptr*) &opt_update_logname, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-slow-queries", OPT_SLOW_QUERY_LOG,
@ -3931,9 +3969,9 @@ replicating a LOAD DATA INFILE command.",
(gptr*) &mysqld_unix_port, (gptr*) &mysqld_unix_port, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"sql-bin-update-same", OPT_SQL_BIN_UPDATE_SAME,
"If set, setting SQL_LOG_BIN to a value will automatically set SQL_LOG_UPDATE to the same value and vice versa.",
(gptr*) &opt_sql_bin_update, (gptr*) &opt_sql_bin_update, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
"The update log is deprecated since version 5.0, is replaced by the binary \
log and this option does nothing anymore.",
0, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"sql-mode", OPT_SQL_MODE,
"Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.",
(gptr*) &sql_mode_str, (gptr*) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0,

View file

@ -335,7 +335,7 @@ send_eof(THD *thd, bool no_flush)
uint tmp= min(thd->total_warn_count, 65535);
buff[0]=254;
int2store(buff+1, tmp);
int2store(buff+3, 0); // No flags yet
int2store(buff+3, thd->server_status);
VOID(my_net_write(net,(char*) buff,5));
VOID(net_flush(net));
}

View file

@ -169,7 +169,7 @@ static int rr_sequential(READ_RECORD *info)
{
if (info->thd->killed)
{
my_error(ER_SERVER_SHUTDOWN,MYF(0));
info->thd->send_kill_message();
return 1;
}
if (tmp != HA_ERR_RECORD_DELETED)

View file

@ -421,7 +421,7 @@ int show_new_master(THD* thd)
DBUG_ENTER("show_new_master");
List<Item> field_list;
char errmsg[SLAVE_ERRMSG_SIZE];
LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
LEX_MASTER_INFO* lex_mi = &thd->lex->mi;
errmsg[0]=0; // Safety
if (translate_master(thd, lex_mi, errmsg))

View file

@ -78,6 +78,7 @@ static void sys_set_default_charset(THD *thd, enum_var_type type);
static bool set_option_bit(THD *thd, set_var *var);
static bool set_option_autocommit(THD *thd, set_var *var);
static bool set_log_update(THD *thd, set_var *var);
static bool set_log_bin(THD *thd, set_var *var);
static void fix_low_priority_updates(THD *thd, enum_var_type type);
static void fix_tx_isolation(THD *thd, enum_var_type type);
static void fix_net_read_timeout(THD *thd, enum_var_type type);
@ -294,7 +295,7 @@ static sys_var_thd_bit sys_log_update("sql_log_update",
set_log_update,
OPTION_UPDATE_LOG);
static sys_var_thd_bit sys_log_binlog("sql_log_bin",
set_log_update,
set_log_bin,
OPTION_BIN_LOG);
static sys_var_thd_bit sys_sql_warnings("sql_warnings",
set_option_bit,
@ -1181,7 +1182,7 @@ byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type)
bool sys_var_thd_bit::update(THD *thd, set_var *var)
{
int res= (*update_func)(thd, var);
thd->lex.select_lex.options=thd->options;
thd->lex->select_lex.options=thd->options;
return res;
}
@ -1572,6 +1573,30 @@ static bool set_option_autocommit(THD *thd, set_var *var)
static bool set_log_update(THD *thd, set_var *var)
{
/*
The update log is not supported anymore since 5.0.
See sql/mysqld.cc/, comments in function init_server_components() for an
explaination of the different warnings we send below
*/
if (opt_sql_bin_update)
{
((sys_var_thd_bit*) var->var)->bit_flag|= (OPTION_BIN_LOG |
OPTION_UPDATE_LOG);
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_UPDATE_LOG_DEPRECATED_TRANSLATED,
ER(ER_UPDATE_LOG_DEPRECATED_TRANSLATED));
}
else
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_UPDATE_LOG_DEPRECATED_IGNORED,
ER(ER_UPDATE_LOG_DEPRECATED_IGNORED));
set_option_bit(thd, var);
return 0;
}
static bool set_log_bin(THD *thd, set_var *var)
{
if (opt_sql_bin_update)
((sys_var_thd_bit*) var->var)->bit_flag|= (OPTION_BIN_LOG |
@ -1580,6 +1605,7 @@ static bool set_log_update(THD *thd, set_var *var)
return 0;
}
static byte *get_warning_count(THD *thd)
{
thd->sys_var_tmp.long_value=

View file

@ -275,3 +275,19 @@ v/*
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"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"
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
"Query execution was interrupted"
"Wrong number of arguments for %s %s, expected %u, got %u"

View file

@ -252,20 +252,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -260,20 +260,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -249,25 +249,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
"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"
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)"
"Z_BUF_ERROR: Not enough memory available for zlib"
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)"
"Z_DATA_ERROR: Input data was corrupted for zlib"
"%d line(s) was(were) cut by group_concat()"
"Record count is fewer than the column count at row %ld";
"Record count is more than the column count at row %ld";
"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
"Data truncated, out of range for column '%s' at row %ld";
"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -254,20 +254,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -249,20 +249,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -258,20 +258,3 @@
"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",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -249,20 +249,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -251,20 +251,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -249,20 +249,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -251,20 +251,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -249,20 +249,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -251,20 +251,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -251,20 +251,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -253,20 +253,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -219,50 +219,3 @@
"Não pode acrescentar uma restrição de chave estrangeira",
"Não pode acrescentar uma linha filha: uma restrição de chave estrangeira falhou",
"Não pode apagar uma linha pai: uma restrição de chave estrangeira falhou",
"Erro connectando para o master: %-.128s",
"Erro rodando consulta no master: %-.128s",
"Erro quando executando comando %s: %-.128s",
"Uso errado de %s e %s",
"Os comandos SELECT usados têm diferentes números de colunas",
"Não pode executar a consulta porque você tem um conflitante travamento de leitura",
"Combinação de tabelas transacionais e não transacionais está desativada",
"Opção '%s' usada duas vezes no comando",
"Usuário '%-.64s' há excedido o '%s' de recursos (atual valor: %ld)",
"Acesso negado. Você necessita o privilégio %-.128s para essa operação",
"Variável '%-.64s' é uma LOCAL variável e não pode ser usada com SET GLOBAL",
"Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL",
"Variável '%-.64s' não tem um valor default (padrão)",
"Variável '%-.64s' não pode ser configurada para o valor de '%-.64s'",
"Tipo de argumento errado para a variável '%-.64s'",
"Variável '%-.64s' somente pode ser configurada, não lida",
"Uso/localização errada de '%s'",
"Esta versão de MySQL não suporta ainda '%s'",
"Obteve fatal error %d: '%-.128s' a partir do master quando lendo dados do binary log",
"Definição errada da chave estrangeira para '%-.64s': %s",
"Referência da chave e referência da tabela não coincidem",
"Error de cardinalidade (mais/menos que %d colunas)",
"Subconsulta retorna mais que 1 registro",
"Desconhecido manipulador de declaração preparado (%ld) determinado para %s",
"Banco de dado de ajuda corrupto ou não existente",
"Referência cíclica em subconsultas",
"Convertendo coluna '%s' de %s para %s",
"Referência '%-.64s' não suportada (%s)",
"Cada tabela derivada deve ter seu próprio alias",
"Select %u foi reduzido durante otimização",
"Tabela '%-.64s' de um dos SELECT's não pode ser usada em %-.32s",
"Cliente não suporta o protocolo de autenticação exigido pelo servidor; considere a atualização deo cliente MySQL",
"Todas as partes de uma SPATIAL KEY devem ser NOT NULL",
"COLLATION '%s' não é válida para CHARACTER SET '%s'",
"O slave já está rodando",
"O slave já está parado",
"Tamanho muito grande dos dados des comprimidos. O máximo tamanho é %d. (provavelmente, o comprimento dos dados descomprimidos está corrupto)",
"Z_BUF_ERROR: Não suficiente memória disponível para zlib",
"Z_MEM_ERROR: Não suficiente espaço no buffer emissor para zlib (provavelmente, o comprimento dos dados descomprimidos está corrupto)",
"Z_DATA_ERROR: Dados de entrada está corrupto para zlib",
"%d linha(s) foi(foram) cortada(s) por group_concat()",
"Usando engine de armazenamento %s para tabela '%s'",
"Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -270,3 +270,19 @@
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"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"
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
"Query execution was interrupted"
"Wrong number of arguments for %s %s, expected %u, got %u"

View file

@ -251,20 +251,3 @@
"Ссылка '%-.64s' не поддерживается (%s)",
"Every derived table must have it's own alias",
"Select %u был упразднен в процессе оптимизации",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -245,20 +245,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -257,20 +257,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -250,20 +250,3 @@
"Reference '%-.64s' not supported (%s)",
"Every derived table must have it's own alias",
"Select %u was reduced during optimisation",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -249,20 +249,3 @@
"Referens '%-.64s' stöds inte (%s)",
"Varje 'derived table' måste ha sitt eget alias",
"Select %u reducerades vid optimiering",
"Tabell '%-.64s' från en SELECT kan inte användas i %-.32s",
"Klienten stöder inte autentiseringsprotokollet som begärts av servern; överväg uppgradering av klientprogrammet.",
"Alla delar av en SPATIAL KEY måste vara NOT NULL",
"COLLATION '%s' är inte tillåtet för CHARACTER SET '%s'",
"Slaven har redan startat",
"Slaven har redan stoppat",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d rad(er) kapades av group_concat()",
"Använder handler %s för tabell '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -254,20 +254,3 @@
"Посилання '%-.64s' не пiдтримуется (%s)",
"Every derived table must have it's own alias",
"Select %u was скасовано при оптимiзацii",
"Table '%-.64s' from one of SELECT's can not be used in %-.32s",
"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",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
"Can't revoke all privileges, grant for one or more of the requested users"
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",

View file

@ -553,7 +553,7 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
if (thd->killed)
{
pthread_mutex_unlock(cond_lock);
DBUG_RETURN(ER_SERVER_SHUTDOWN);
DBUG_RETURN(thd->killed_errno());
}
}
}
@ -1846,7 +1846,7 @@ err:
pthread_mutex_unlock(&data_lock);
DBUG_PRINT("exit",("killed: %d abort: %d slave_running: %d \
improper_arguments: %d timed_out: %d",
(int) thd->killed,
thd->killed_errno(),
(int) (init_abort_pos_wait != abort_pos_wait),
(int) mi->slave_running,
(int) (error == -2),

450
sql/sp.cc Normal file
View file

@ -0,0 +1,450 @@
/* 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"
#include "sp_cache.h"
/*
*
* DB storage of Stored PROCEDUREs and FUNCTIONs
*
*/
// *opened=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);
TABLE *table;
const char *defstr;
int ret;
bool opened;
const char *creator;
longlong created;
longlong modified;
bool suid= 1;
char *ptr;
uint length;
char buff[65];
String str(buff, sizeof(buff), &my_charset_bin);
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;
}
// Get additional information
if ((creator= get_field(&thd->mem_root, table->field[3])) == NULL)
{
ret= SP_GET_FIELD_FAILED;
goto done;
}
modified= table->field[4]->val_int();
created= table->field[5]->val_int();
if ((ptr= get_field(&thd->mem_root, table->field[6])) == NULL)
{
ret= SP_GET_FIELD_FAILED;
goto done;
}
if (ptr[0] == 'N')
suid= 0;
table->field[7]->val_str(&str, &str);
ptr= 0;
if ((length= str.length()))
ptr= strmake_root(&thd->mem_root, str.ptr(), length);
if (opened)
{
close_thread_tables(thd, 0, 1);
table= NULL;
}
{
LEX *oldlex= thd->lex;
enum enum_sql_command oldcmd= thd->lex->sql_command;
lex_start(thd, (uchar*)defstr, strlen(defstr));
if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)
{
LEX *newlex= thd->lex;
sp_head *sp= newlex->sphead;
if (sp)
{
if (oldlex != newlex)
sp->restore_lex(thd);
delete sp;
newlex->sphead= NULL;
}
ret= SP_PARSE_ERROR;
}
else
{
*sphp= thd->lex->sphead;
(*sphp)->sp_set_info((char *) creator, (uint) strlen(creator),
created, modified, suid,
ptr, length);
}
thd->lex->sql_command= oldcmd;
}
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,
char *comment, uint commentlen, bool suid)
{
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;
char creator[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
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
strxmov(creator, thd->user, "@", thd->host_or_ip, NullS);
table->field[0]->store(name, namelen, system_charset_info);
table->field[1]->store((longlong)type);
table->field[2]->store(def, deflen, system_charset_info);
table->field[3]->store(creator, (uint)strlen(creator), system_charset_info);
((Field_timestamp *)table->field[5])->set_time();
if (suid)
table->field[6]->store((longlong)suid);
if (comment)
table->field[7]->store(comment, commentlen, 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));
sp= thd->sp_proc_cache->lookup(name->str, name->length);
if (! sp)
{
if (db_find_routine(thd, TYPE_ENUM_PROCEDURE,
name->str, name->length, &sp) == SP_OK)
{
thd->sp_proc_cache->insert(sp);
}
}
DBUG_RETURN(sp);
}
int
sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen,
char *comment, uint commentlen, bool suid)
{
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,
comment, commentlen, suid);
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));
sp_head *sp;
int ret;
sp= thd->sp_proc_cache->lookup(name, namelen);
if (sp)
{
thd->sp_proc_cache->remove(sp);
delete sp;
}
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= thd->sp_func_cache->lookup(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,
char *comment, uint commentlen, bool suid)
{
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,
comment, commentlen, suid);
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));
sp_head *sp;
int ret;
sp= thd->sp_func_cache->lookup(name, namelen);
if (sp)
{
thd->sp_func_cache->remove(sp);
delete sp;
}
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= FALSE;
if (thd->sp_func_cache->lookup(name->str, name->length) ||
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, 0, 1);
return ret;
}
byte *
sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first)
{
LEX_STRING *lsp= (LEX_STRING *)ptr;
*plen= lsp->length;
return (byte *)lsp->str;
}
void
sp_add_fun_to_lex(LEX *lex, LEX_STRING fun)
{
if (! hash_search(&lex->spfuns, (byte *)fun.str, fun.length))
{
LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING));
ls->str= sql_strmake(fun.str, fun.length);
ls->length= fun.length;
hash_insert(&lex->spfuns, (byte *)ls);
}
}
void
sp_merge_funs(LEX *dst, LEX *src)
{
for (uint i=0 ; i < src->spfuns.records ; i++)
{
LEX_STRING *ls= (LEX_STRING *)hash_element(&src->spfuns, i);
if (! hash_search(&dst->spfuns, (byte *)ls->str, ls->length))
hash_insert(&dst->spfuns, (byte *)ls);
}
}
int
sp_cache_functions(THD *thd, LEX *lex)
{
HASH *h= &lex->spfuns;
int ret= 0;
for (uint i=0 ; i < h->records ; i++)
{
LEX_STRING *ls= (LEX_STRING *)hash_element(h, i);
if (! thd->sp_func_cache->lookup(ls->str, ls->length))
{
sp_head *sp;
LEX *oldlex= thd->lex;
LEX *newlex= new st_lex;
thd->lex= newlex;
if (db_find_routine(thd, TYPE_ENUM_FUNCTION, ls->str, ls->length, &sp)
== SP_OK)
{
ret= sp_cache_functions(thd, newlex);
delete newlex;
thd->lex= oldlex;
if (ret)
break;
thd->sp_func_cache->insert(sp);
}
else
{
delete newlex;
thd->lex= oldlex;
net_printf(thd, ER_SP_DOES_NOT_EXIST, "FUNCTION", ls->str);
ret= 1;
break;
}
}
}
return ret;
}

65
sql/sp.h Normal file
View file

@ -0,0 +1,65 @@
/* -*- 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,
char *comment, uint commentlen, bool suid);
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,
char *comment, uint commentlen, bool suid);
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);
// 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);
#endif /* _SP_H_ */

53
sql/sp_cache.cc Normal file
View file

@ -0,0 +1,53 @@
/* 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_cache.h"
#include "sp_head.h"
static byte *
hash_get_key_for_sp_head(const byte *ptr, uint *plen,
my_bool first)
{
return ((sp_head*)ptr)->name(plen);
}
sp_cache::sp_cache()
{
init();
}
sp_cache::~sp_cache()
{
hash_free(&m_hashtable);
}
void
sp_cache::init()
{
hash_init(&m_hashtable, system_charset_info, 0, 0, 0,
hash_get_key_for_sp_head, 0, 0);
}
void
sp_cache::cleanup()
{
hash_free(&m_hashtable);
}

65
sql/sp_cache.h Normal file
View file

@ -0,0 +1,65 @@
/* -*- 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_CACHE_H_
#define _SP_CACHE_H_
#ifdef __GNUC__
#pragma interface /* gcc class implementation */
#endif
class sp_head;
class sp_cache
{
public:
sp_cache();
~sp_cache();
void
init();
void
cleanup();
inline void
insert(sp_head *sp)
{
hash_insert(&m_hashtable, (const byte *)sp);
}
inline sp_head *
lookup(char *name, uint namelen)
{
return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen);
}
inline void
remove(sp_head *sp)
{
hash_delete(&m_hashtable, (byte *)sp);
}
private:
HASH m_hashtable;
}; // class sp_cache
#endif /* _SP_CACHE_H_ */

645
sql/sp_head.cc Normal file
View file

@ -0,0 +1,645 @@
/* 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"
Item_result
sp_map_result_type(enum enum_field_types type)
{
switch (type)
{
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_INT24:
return INT_RESULT;
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
return REAL_RESULT;
default:
return STRING_RESULT;
}
}
/* 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)
{
DBUG_ENTER("eval_func_item");
it= it->this_item();
DBUG_PRINT("info", ("type: %d", type));
if (it->fix_fields(thd, 0, &it))
{
DBUG_PRINT("info", ("fix_fields() failed"));
DBUG_RETURN(it); // Shouldn't happen?
}
/* QQ How do we do this? Is there some better way? */
if (type == MYSQL_TYPE_NULL)
it= new Item_null();
else
{
switch (sp_map_result_type(type)) {
case INT_RESULT:
DBUG_PRINT("info", ("INT_RESULT: %d", it->val_int()));
it= new Item_int(it->val_int());
break;
case REAL_RESULT:
DBUG_PRINT("info", ("REAL_RESULT: %g", it->val()));
it= new Item_real(it->val());
break;
default:
{
char buffer[MAX_FIELD_WIDTH];
String tmp(buffer, sizeof(buffer), it->charset());
String *s= it->val_str(&tmp);
DBUG_PRINT("info",("default result: %*s",s->length(),s->c_ptr_quick()));
it= new Item_string(thd->strmake(s->c_ptr_quick(), s->length()),
s->length(), it->charset());
break;
}
}
}
DBUG_RETURN(it);
}
void *
sp_head::operator new(size_t size)
{
DBUG_ENTER("sp_head::operator new");
MEM_ROOT own_root;
sp_head *sp;
bzero((char *)&own_root, sizeof(own_root));
init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
sp= (sp_head *)alloc_root(&own_root, size);
sp->m_mem_root= own_root;
DBUG_RETURN(sp);
}
void
sp_head::operator delete(void *ptr, size_t size)
{
DBUG_ENTER("sp_head::operator delete");
MEM_ROOT own_root;
sp_head *sp= (sp_head *)ptr;
memcpy(&own_root, (const void *)&sp->m_mem_root, sizeof(MEM_ROOT));
free_root(&own_root, MYF(0));
DBUG_VOID_RETURN;
}
sp_head::sp_head()
: Sql_alloc(), m_simple_case(FALSE), m_multi_query(FALSE), m_free_list(NULL)
{
DBUG_ENTER("sp_head::sp_head");
m_backpatch.empty();
m_lex.empty();
DBUG_VOID_RETURN;
}
void
sp_head::init(LEX_STRING *name, LEX *lex, LEX_STRING *comment, char suid)
{
DBUG_ENTER("sp_head::init");
const char *dstr = (const char*)lex->buf;
DBUG_PRINT("info", ("name: %*s", name->length, name->str));
m_name.length= name->length;
m_name.str= lex->thd->strmake(name->str, name->length);
m_defstr.length= lex->end_of_query - lex->buf;
m_defstr.str= lex->thd->strmake(dstr, m_defstr.length);
m_comment.length= 0;
m_comment.str= 0;
if (comment)
{
m_comment.length= comment->length;
m_comment.str= comment->str;
}
m_suid= suid;
lex->spcont= m_pcont= new sp_pcontext();
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
DBUG_VOID_RETURN;
}
int
sp_head::create(THD *thd)
{
DBUG_ENTER("sp_head::create");
int ret;
DBUG_PRINT("info", ("type: %d name: %s def: %s",
m_type, m_name.str, m_defstr.str));
if (m_type == TYPE_ENUM_FUNCTION)
ret= sp_create_function(thd,
m_name.str, m_name.length,
m_defstr.str, m_defstr.length,
m_comment.str, m_comment.length,
m_suid);
else
ret= sp_create_procedure(thd,
m_name.str, m_name.length,
m_defstr.str, m_defstr.length,
m_comment.str, m_comment.length,
m_suid);
DBUG_RETURN(ret);
}
sp_head::~sp_head()
{
destroy();
if (m_thd)
restore_thd_mem_root(m_thd);
}
void
sp_head::destroy()
{
DBUG_ENTER("sp_head::destroy");
DBUG_PRINT("info", ("name: %s", m_name.str));
sp_instr *i;
LEX *lex;
for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
delete i;
delete_dynamic(&m_instr);
m_pcont->destroy();
free_items(m_free_list);
while ((lex= (LEX *)m_lex.pop()))
{
if (lex != &m_thd->main_lex) // We got interrupted and have lex'es left
delete lex;
}
DBUG_VOID_RETURN;
}
int
sp_head::execute(THD *thd)
{
DBUG_ENTER("sp_head::execute");
char olddbname[128];
char *olddbptr= thd->db;
int ret= 0;
uint ip= 0;
if (olddbptr)
{
uint i= 0;
char *p= olddbptr;
/* Fast inline strncpy without padding... */
while (*p && i < sizeof(olddbname))
olddbname[i++]= *p++;
if (i == sizeof(olddbname))
i-= 1; // QQ Error or warning for truncate?
olddbname[i]= '\0';
}
do
{
sp_instr *i;
i = get_instr(ip); // Returns NULL when we're done.
if (i == NULL)
break;
DBUG_PRINT("execute", ("Instruction %u", ip));
ret= i->execute(thd, &ip);
} while (ret == 0 && !thd->killed);
DBUG_PRINT("info", ("ret=%d killed=%d", ret, thd->killed));
if (thd->killed)
ret= -1;
/* If the DB has changed, the pointer has changed too, but the
original thd->db will then have been freed */
if (olddbptr && olddbptr != thd->db)
{
/* QQ Maybe we should issue some special error message or warning here,
if this fails?? */
if (! thd->killed)
ret= mysql_change_db(thd, olddbname);
}
DBUG_RETURN(ret);
}
int
sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
{
DBUG_ENTER("sp_head::execute_function");
DBUG_PRINT("info", ("function %s", m_name.str));
uint csize = m_pcont->max_framesize();
uint params = m_pcont->params();
sp_rcontext *octx = thd->spcont;
sp_rcontext *nctx = NULL;
uint i;
int ret;
if (argcount != params)
{
// Need to use my_printf_error here, or it will not terminate the
// invoking query properly.
my_printf_error(ER_SP_WRONG_NO_OF_ARGS, ER(ER_SP_WRONG_NO_OF_ARGS), MYF(0),
"FUNCTION", m_name.str, params, argcount);
DBUG_RETURN(-1);
}
// QQ Should have some error checking here? (types, etc...)
nctx= new sp_rcontext(csize);
for (i= 0 ; i < params && i < argcount ; i++)
{
sp_pvar_t *pvar = m_pcont->find_pvar(i);
nctx->push_item(eval_func_item(thd, *argp++, pvar->type));
}
// Close tables opened for subselect in argument list
close_thread_tables(thd);
// The rest of the frame are local variables which are all IN.
// QQ See comment in execute_procedure below.
for (; i < csize ; i++)
nctx->push_item(NULL);
thd->spcont= nctx;
ret= execute(thd);
if (ret == 0)
*resp= nctx->get_result();
thd->spcont= octx;
DBUG_RETURN(ret);
}
int
sp_head::execute_procedure(THD *thd, List<Item> *args)
{
DBUG_ENTER("sp_head::execute_procedure");
DBUG_PRINT("info", ("procedure %s", m_name.str));
int ret;
sp_instr *p;
uint csize = m_pcont->max_framesize();
uint params = m_pcont->params();
sp_rcontext *octx = thd->spcont;
sp_rcontext *nctx = NULL;
my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
if (args->elements != params)
{
net_printf(thd, ER_SP_WRONG_NO_OF_ARGS, "PROCEDURE", m_name.str,
params, args->elements);
DBUG_RETURN(-1);
}
if (csize > 0)
{
uint i;
List_iterator_fast<Item> li(*args);
Item *it;
nctx = new sp_rcontext(csize);
if (! octx)
{ // Create a temporary old context
octx = new sp_rcontext(csize);
tmp_octx = TRUE;
}
// QQ: Should do type checking?
for (i = 0 ; (it= li++) && i < params ; i++)
{
sp_pvar_t *pvar = m_pcont->find_pvar(i);
if (! pvar)
nctx->set_oindex(i, -1); // Shouldn't happen
else
{
if (pvar->mode == sp_param_out)
nctx->push_item(NULL); // 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());
}
}
// Close tables opened for subselect in argument list
close_thread_tables(thd);
// The rest of the frame are local variables which are all IN.
// QQ We haven't found any hint of what the value is when unassigned,
// so we set it to NULL for now. It's an error to refer to an
// unassigned variable anyway (which should be detected by the parser).
for (; i < csize ; i++)
nctx->push_item(NULL);
thd->spcont= nctx;
}
ret= execute(thd);
// Don't copy back OUT values if we got an error
if (ret == 0 && csize > 0)
{
List_iterator_fast<Item> li(*args);
Item *it;
// Copy back all OUT or INOUT values to the previous frame, or
// set global user variables
for (uint i = 0 ; (it= li++) && i < params ; i++)
{
int oi = nctx->get_oindex(i);
if (oi >= 0)
{
if (! tmp_octx)
octx->set_item(nctx->get_oindex(i), nctx->get_item(i));
else
{ // A global user variable
#if NOT_USED_NOW
// QQ This works if the parameter really is a user variable, but
// for the moment we can't assure that, so it will crash if it's
// something else. So for now, we just do nothing, to avoid a crash.
// Note: This also assumes we have a get_name() method in
// the Item_func_get_user_var class.
Item *item= nctx->get_item(i);
Item_func_set_user_var *suv;
Item_func_get_user_var *guv= static_cast<Item_func_get_user_var*>(it);
suv= new Item_func_set_user_var(guv->get_name(), item);
suv->fix_fields(thd, NULL, &item);
suv->fix_length_and_dec();
suv->update();
#endif
}
}
}
if (tmp_octx)
thd->spcont= NULL;
else
thd->spcont= octx;
}
DBUG_RETURN(ret);
}
// Reset lex during parsing, before we parse a sub statement.
void
sp_head::reset_lex(THD *thd)
{
DBUG_ENTER("sp_head::reset_lex");
LEX *sublex;
LEX *oldlex= thd->lex;
(void)m_lex.push_front(oldlex);
thd->lex= sublex= new st_lex;
sublex->yylineno= oldlex->yylineno;
/* Reset most stuff. The length arguments doesn't matter here. */
lex_start(thd, oldlex->buf, oldlex->end_of_query - oldlex->ptr);
/* We must reset ptr and end_of_query again */
sublex->ptr= oldlex->ptr;
sublex->end_of_query= oldlex->end_of_query;
sublex->tok_start= oldlex->tok_start;
/* And keep the SP stuff too */
sublex->sphead= oldlex->sphead;
sublex->spcont= oldlex->spcont;
mysql_init_query(thd, true); // Only init lex
sublex->sp_lex_in_use= FALSE;
DBUG_VOID_RETURN;
}
// Restore lex during parsing, after we have parsed a sub statement.
void
sp_head::restore_lex(THD *thd)
{
DBUG_ENTER("sp_head::restore_lex");
LEX *sublex= thd->lex;
LEX *oldlex= (LEX *)m_lex.pop();
if (! oldlex)
return; // Nothing to restore
// Update some state in the old one first
oldlex->ptr= sublex->ptr;
oldlex->next_state= sublex->next_state;
// Collect some data from the sub statement lex.
sp_merge_funs(oldlex, sublex);
#ifdef NOT_USED_NOW
// QQ We're not using this at the moment.
if (sublex.sql_command == SQLCOM_CALL)
{
// It would be slightly faster to keep the list sorted, but we need
// an "insert before" method to do that.
char *proc= sublex.udf.name.str;
List_iterator_fast<char *> li(m_calls);
char **it;
while ((it= li++))
if (my_strcasecmp(system_charset_info, proc, *it) == 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= sublex.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 (my_strcasecmp(system_charset_info, tables->real_name, *tb) == 0)
break;
if (! tb)
m_tables.push_back(&tables->real_name);
}
}
#endif
if (! sublex->sp_lex_in_use)
delete sublex;
thd->lex= oldlex;
DBUG_VOID_RETURN;
}
void
sp_head::push_backpatch(sp_instr *i, sp_label_t *lab)
{
bp_t *bp= (bp_t *)sql_alloc(sizeof(bp_t));
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
//
sp_instr_stmt::~sp_instr_stmt()
{
if (m_lex)
delete m_lex;
}
int
sp_instr_stmt::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_stmt::execute");
DBUG_PRINT("info", ("command: %d", m_lex->sql_command));
LEX *olex; // The other lex
int res;
olex= thd->lex; // Save the other lex
thd->lex= m_lex; // Use my own lex
thd->lex->thd = thd; // QQ Not reentrant!
thd->lex->unit.thd= thd; // QQ Not reentrant
res= mysql_execute_command(thd);
if (thd->lock || thd->open_tables || thd->derived_tables)
{
thd->proc_info="closing tables";
close_thread_tables(thd); /* Free tables */
}
thd->lex= olex; // Restore the other lex
*nextp = m_ip+1;
DBUG_RETURN(res);
}
//
// sp_instr_set
//
int
sp_instr_set::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_set::execute");
DBUG_PRINT("info", ("offset: %u", m_offset));
thd->spcont->set_item(m_offset, eval_func_item(thd, m_value, m_type));
*nextp = m_ip+1;
DBUG_RETURN(0);
}
//
// sp_instr_jump
//
int
sp_instr_jump::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_jump::execute");
DBUG_PRINT("info", ("destination: %u", m_dest));
*nextp= m_dest;
DBUG_RETURN(0);
}
//
// sp_instr_jump_if
//
int
sp_instr_jump_if::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_jump_if::execute");
DBUG_PRINT("info", ("destination: %u", m_dest));
Item *it= eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
if (it->val_int())
*nextp = m_dest;
else
*nextp = m_ip+1;
DBUG_RETURN(0);
}
//
// sp_instr_jump_if_not
//
int
sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_jump_if_not::execute");
DBUG_PRINT("info", ("destination: %u", m_dest));
Item *it= eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
if (! it->val_int())
*nextp = m_dest;
else
*nextp = m_ip+1;
DBUG_RETURN(0);
}
//
// sp_instr_return
//
int
sp_instr_return::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_return::execute");
thd->spcont->set_result(eval_func_item(thd, m_value, m_type));
*nextp= UINT_MAX;
DBUG_RETURN(0);
}

411
sql/sp_head.h Normal file
View file

@ -0,0 +1,411 @@
/* -*- 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
my_bool m_multi_query; // TRUE if a procedure with SELECT(s)
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
#if NOT_USED_NOW
// QQ 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);
static void
operator delete(void *ptr, size_t size);
sp_head();
// Initialize after we have reset mem_root
void
init(LEX_STRING *name, LEX *lex, LEX_STRING *comment, char suid);
int
create(THD *thd);
virtual ~sp_head();
// Free memory
void
destroy();
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
{
if (lenp)
*lenp= m_name.length;
return m_name.str;
}
inline Item_result result()
{
return sp_map_result_type(m_returns);
}
void sp_set_info(char *creator, uint creatorlen,
longlong created, longlong modified,
bool suid, char *comment, uint commentlen)
{
m_creator= creator;
m_creatorlen= creatorlen;
m_created= created;
m_modified= modified;
m_comment.length= commentlen;
m_comment.str= comment;
m_suid= suid;
}
inline void reset_thd_mem_root(THD *thd)
{
m_thd_root= thd->mem_root;
thd->mem_root= m_mem_root;
m_free_list= thd->free_list; // Keep the old list
thd->free_list= NULL; // Start a new one
m_thd= thd;
}
inline void restore_thd_mem_root(THD *thd)
{
Item *flist= m_free_list; // The old list
m_free_list= thd->free_list; // Get the new one
thd->free_list= flist; // Restore the old one
m_mem_root= thd->mem_root;
thd->mem_root= m_thd_root;
m_thd= NULL;
}
private:
MEM_ROOT m_mem_root; // My own mem_root
MEM_ROOT m_thd_root; // Temp. store for thd's mem_root
Item *m_free_list; // Where the items go
THD *m_thd; // Set if we have reset mem_root
LEX_STRING m_name;
LEX_STRING m_defstr;
LEX_STRING m_comment;
char *m_creator;
uint m_creatorlen;
longlong m_created;
longlong m_modified;
bool m_suid;
sp_pcontext *m_pcont; // Parse context
List<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 *ip;
if (i < m_instr.elements)
get_dynamic(&m_instr, (gptr)&ip, i);
else
ip= NULL;
return ip;
}
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), m_lex(NULL)
{}
virtual ~sp_instr_stmt();
virtual int execute(THD *thd, uint *nextp);
inline void
set_lex(LEX *lex)
{
m_lex= 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_ */

115
sql/sp_pcontext.cc Normal file
View file

@ -0,0 +1,115 @@
/* 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()
: Sql_alloc(), m_params(0), m_framesize(0), m_genlab(0)
{
VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
m_label.empty();
}
void
sp_pcontext::destroy()
{
delete_dynamic(&m_pvar);
m_label.empty();
}
/* 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)
{
uint i = m_pvar.elements;
while (i-- > 0)
{
sp_pvar_t *p= find_pvar(i);
if (my_strnncoll(system_charset_info,
(const uchar *)name->str, name->length,
(const uchar *)p->name.str, p->name.length) == 0)
{
return p;
}
}
return NULL;
}
void
sp_pcontext::push(LEX_STRING *name, enum enum_field_types type,
sp_param_mode_t mode)
{
sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t));
if (p)
{
if (m_pvar.elements == m_framesize)
m_framesize += 1;
p->name.str= name->str;
p->name.length= name->length;
p->type= type;
p->mode= mode;
p->offset= m_pvar.elements;
p->isset= (mode == sp_param_out ? FALSE : TRUE);
insert_dynamic(&m_pvar, (gptr)&p);
}
}
sp_label_t *
sp_pcontext::push_label(char *name, uint ip)
{
sp_label_t *lab = (sp_label_t *)sql_alloc(sizeof(sp_label_t));
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 (my_strcasecmp(system_charset_info, name, lab->name) == 0)
return lab;
return NULL;
}

162
sql/sp_pcontext.h Normal file
View file

@ -0,0 +1,162 @@
/* -*- 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
{
LEX_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();
// Free memory
void
destroy();
inline uint
max_framesize()
{
return m_framesize;
}
inline uint
current_framesize()
{
return m_pvar.elements;
}
inline uint
params()
{
return m_params;
}
// Set the number of parameters to the current esize
inline void
set_params()
{
m_params= m_pvar.elements;
}
inline void
set_type(uint i, enum enum_field_types type)
{
sp_pvar_t *p= find_pvar(i);
if (p)
p->type= type;
}
inline void
set_isset(uint i, my_bool val)
{
sp_pvar_t *p= find_pvar(i);
if (p)
p->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)
{
while (num--)
pop_dynamic(&m_pvar);
}
// Find by name
sp_pvar_t *
find_pvar(LEX_STRING *name);
// Find by index
sp_pvar_t *
find_pvar(uint i)
{
sp_pvar_t *p;
if (i < m_pvar.elements)
get_dynamic(&m_pvar, (gptr)&p, i);
else
p= NULL;
return p;
}
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
DYNAMIC_ARRAY m_pvar;
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_ */

95
sql/sp_rcontext.h Normal file
View file

@ -0,0 +1,95 @@
/* -*- 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_ */

View file

@ -1186,7 +1186,6 @@ bool change_password(THD *thd, const char *host, const char *user,
acl_user->user ? acl_user->user : "",
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password));
mysql_update_log.write(thd, buff, query_length);
Query_log_event qinfo(thd, buff, query_length, 0);
mysql_bin_log.write(&qinfo);
DBUG_RETURN(0);
@ -1424,7 +1423,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
if (table->fields >= 31) /* From 4.0.0 we have more fields */
{
/* We write down SSL related ACL stuff */
switch (thd->lex.ssl_type) {
switch (thd->lex->ssl_type) {
case SSL_TYPE_ANY:
table->field[24]->store("ANY",3, &my_charset_latin1);
table->field[25]->store("", 0, &my_charset_latin1);
@ -1442,15 +1441,15 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
table->field[25]->store("", 0, &my_charset_latin1);
table->field[26]->store("", 0, &my_charset_latin1);
table->field[27]->store("", 0, &my_charset_latin1);
if (thd->lex.ssl_cipher)
table->field[25]->store(thd->lex.ssl_cipher,
strlen(thd->lex.ssl_cipher), &my_charset_latin1);
if (thd->lex.x509_issuer)
table->field[26]->store(thd->lex.x509_issuer,
strlen(thd->lex.x509_issuer), &my_charset_latin1);
if (thd->lex.x509_subject)
table->field[27]->store(thd->lex.x509_subject,
strlen(thd->lex.x509_subject), &my_charset_latin1);
if (thd->lex->ssl_cipher)
table->field[25]->store(thd->lex->ssl_cipher,
strlen(thd->lex->ssl_cipher), &my_charset_latin1);
if (thd->lex->x509_issuer)
table->field[26]->store(thd->lex->x509_issuer,
strlen(thd->lex->x509_issuer), &my_charset_latin1);
if (thd->lex->x509_subject)
table->field[27]->store(thd->lex->x509_subject,
strlen(thd->lex->x509_subject), &my_charset_latin1);
break;
case SSL_TYPE_NOT_SPECIFIED:
break;
@ -1462,7 +1461,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
break;
}
USER_RESOURCES mqh = thd->lex.mqh;
USER_RESOURCES mqh = thd->lex->mqh;
if (mqh.bits & 1)
table->field[28]->store((longlong) mqh.questions);
if (mqh.bits & 2)
@ -1505,19 +1504,19 @@ end:
password=0; // No password given on command
if (old_row_exists)
acl_update_user(combo.user.str,combo.host.str,password,
thd->lex.ssl_type,
thd->lex.ssl_cipher,
thd->lex.x509_issuer,
thd->lex.x509_subject,
&thd->lex.mqh,
thd->lex->ssl_type,
thd->lex->ssl_cipher,
thd->lex->x509_issuer,
thd->lex->x509_subject,
&thd->lex->mqh,
rights);
else
acl_insert_user(combo.user.str,combo.host.str,password,
thd->lex.ssl_type,
thd->lex.ssl_cipher,
thd->lex.x509_issuer,
thd->lex.x509_subject,
&thd->lex.mqh,
thd->lex->ssl_type,
thd->lex->ssl_cipher,
thd->lex->x509_issuer,
thd->lex->x509_subject,
&thd->lex->mqh,
rights);
}
table->file->index_end();

View file

@ -2416,7 +2416,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
/* Kill delayed insert threads */
if (in_use->system_thread && ! in_use->killed)
{
in_use->killed=1;
in_use->killed= THD::KILL_CONNECTION;
pthread_mutex_lock(&in_use->mysys_var->mutex);
if (in_use->mysys_var->current_cond)
{

View file

@ -897,7 +897,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
/* Check that we haven't forgot to reset the query cache variables */
DBUG_ASSERT(thd->net.query_cache_query == 0);
if (!thd->lex.safe_to_cache_query)
if (!thd->lex->safe_to_cache_query)
{
DBUG_PRINT("qcache", ("SELECT is non-cacheable"));
goto err;
@ -1000,7 +1000,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
table_list.db, table_list.alias));
refused++; // This is actually a hit
STRUCT_UNLOCK(&structure_guard_mutex);
thd->lex.safe_to_cache_query=0; // Don't try to cache this
thd->lex->safe_to_cache_query=0; // Don't try to cache this
BLOCK_UNLOCK_RD(query_block);
DBUG_RETURN(-1); // Privilege error
}
@ -1009,7 +1009,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s",
table_list.db, table_list.alias));
BLOCK_UNLOCK_RD(query_block);
thd->lex.safe_to_cache_query= 0; // Don't try to cache this
thd->lex->safe_to_cache_query= 0; // Don't try to cache this
goto err_unlock; // Parse query
}
if (check_tables && !handler::caching_allowed(thd, table->db(),
@ -1019,7 +1019,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
table_list.db, table_list.alias));
BLOCK_UNLOCK_RD(query_block);
thd->lex.safe_to_cache_query= 0; // Don't try to cache this
thd->lex->safe_to_cache_query= 0; // Don't try to cache this
goto err_unlock; // Parse query
}
else
@ -2959,7 +2959,7 @@ void Query_cache::wreck(uint line, const char *message)
DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line));
DBUG_PRINT("warning", ("=================================="));
if (thd)
thd->killed = 1;
thd->killed= THD::KILL_CONNECTION;
cache_dump();
/* check_integrity(0); */ /* Can't call it here because of locks */
bins_dump();

View file

@ -36,6 +36,9 @@
#endif
#include <mysys_err.h>
#include <sp_rcontext.h>
#include <sp_cache.h>
/*
The following is used to initialise Table_ident with a internal
table name
@ -86,12 +89,14 @@ 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)
{
lex= &main_lex;
host=user=priv_user=db=query=ip=0;
host_or_ip= "connecting host";
locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password=
locked=count_cuted_fields=some_tables_deleted=no_errors=password=
query_start_used=prepare_command=0;
killed= NOT_KILLED;
db_length=query_length=col_access=0;
query_error= tmp_table_used= 0;
next_insert_id=last_insert_id=0;
@ -148,9 +153,12 @@ THD::THD():user_time(0), is_fatal_error(0),
bzero((char*) &warn_root,sizeof(warn_root));
init_alloc_root(&warn_root, 1024, 0);
user_connect=(USER_CONN *)0;
hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
(hash_free_key) free_user_var,0);
(hash_free_key) free_user_var, 0);
sp_proc_cache= new sp_cache();
sp_func_cache= new sp_cache();
/* For user vars replication*/
if (opt_bin_log)
@ -181,7 +189,7 @@ THD::THD():user_time(0), is_fatal_error(0),
if (open_cached_file(&transaction.trans_log,
mysql_tmpdir, LOG_PREFIX, binlog_cache_size,
MYF(MY_WME)))
killed=1;
killed= KILL_CONNECTION;
transaction.trans_log.end_of_file= max_binlog_cache_size;
}
#endif
@ -251,9 +259,11 @@ void THD::change_user(void)
cleanup();
cleanup_done= 0;
init();
hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
(hash_free_key) free_user_var, 0);
sp_proc_cache->init();
sp_func_cache->init();
}
@ -277,6 +287,8 @@ void THD::cleanup(void)
close_temporary_tables(this);
delete_dynamic(&user_var_events);
hash_free(&user_vars);
sp_proc_cache->cleanup();
sp_func_cache->cleanup();
if (global_read_lock)
unlock_global_read_lock(this);
if (ull)
@ -286,6 +298,7 @@ void THD::cleanup(void)
pthread_mutex_unlock(&LOCK_user_locks);
ull= 0;
}
cleanup_done=1;
DBUG_VOID_RETURN;
}
@ -317,6 +330,9 @@ THD::~THD()
}
#endif
delete sp_proc_cache;
delete sp_func_cache;
DBUG_PRINT("info", ("freeing host"));
if (host != localhost) // If not pointer to constant
safeFree(host);
@ -337,14 +353,14 @@ THD::~THD()
}
void THD::awake(bool prepare_to_die)
void THD::awake(THD::killed_state state_to_set)
{
THD_CHECK_SENTRY(this);
safe_mutex_assert_owner(&LOCK_delete);
if (prepare_to_die)
killed = 1;
thr_alarm_kill(real_id);
killed= state_to_set;
if (state_to_set != THD::KILL_QUERY)
thr_alarm_kill(real_id);
#ifdef SIGNAL_WITH_VIO_CLOSE
close_active_vio();
#endif
@ -461,7 +477,7 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
{
my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
killed= 1;
killed= KILL_CONNECTION;
return 0;
}
@ -1007,9 +1023,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));
@ -1018,19 +1037,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
@ -1042,8 +1081,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);
}

View file

@ -26,6 +26,8 @@
class Query_log_event;
class Load_log_event;
class Slave_log_event;
class sp_rcontext;
class sp_cache;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY };
@ -407,7 +409,8 @@ public:
struct st_mysql *mysql;
#endif
NET net; // client connection descriptor
LEX lex; // parse tree descriptor
LEX main_lex;
LEX *lex; // parse tree descriptor
MEM_ROOT mem_root; // 1 command-life memory pool
MEM_ROOT con_root; // connection-life memory
MEM_ROOT warn_root; // For warnings and errors
@ -556,9 +559,23 @@ public:
bool query_start_used,last_insert_id_used,insert_id_used,rand_used;
bool system_thread,in_lock_tables,global_read_lock;
bool query_error, bootstrap, cleanup_done;
bool volatile killed;
enum killed_state { NOT_KILLED=0, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED };
killed_state volatile killed;
inline int killed_errno() const
{
return killed;
}
inline void send_kill_message() const
{
my_error(killed_errno(), MYF(0));
}
bool prepare_command;
bool tmp_table_used;
sp_rcontext *spcont; // SP runtime context
sp_cache *sp_proc_cache;
sp_cache *sp_func_cache;
/*
If we do a purge of binary logs, log index info of the threads
@ -598,7 +615,7 @@ public:
}
void close_active_vio();
#endif
void awake(bool prepare_to_die);
void awake(THD::killed_state state_to_set);
inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex,
const char* msg)
{
@ -1072,13 +1089,22 @@ public:
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;}

Some files were not shown because too many files have changed in this diff Show more