mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
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:
commit
d6b336359a
119 changed files with 6324 additions and 929 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
622
Docs/sp-imp-spec.txt
Normal 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
99
Docs/sp-implemented.txt
Normal 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.
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
18
configure.in
18
configure.in
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,...));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -64,3 +64,16 @@ use test_$1;
|
|||
create table t1 (c int);
|
||||
insert into test_$1.t1 set test_$1.t1.c = '1';
|
||||
drop database test_$1;
|
||||
use test;
|
||||
drop table if exists t1,t2,t3;
|
||||
create table t1(id1 int not null auto_increment primary key, t char(12));
|
||||
create table t2(id2 int not null, t char(12));
|
||||
create table t3(id3 int not null, t char(12), index(id3));
|
||||
select count(*) from t2;
|
||||
count(*)
|
||||
500
|
||||
insert into t2 select t1.* from t1, t2 t, t3 where t1.id1 = t.id2 and t.id2 = t3.id3;
|
||||
select count(*) from t2;
|
||||
count(*)
|
||||
25500
|
||||
drop table if exists t1,t2,t3;
|
||||
|
|
|
@ -127,6 +127,7 @@ insert into t1 values (1);
|
|||
show open tables;
|
||||
Database Table In_use Name_locked
|
||||
test t1 0 0
|
||||
mysql proc 0 0
|
||||
drop table t1;
|
||||
create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CHECKSUM=1 COMMENT="test" TYPE=MYISAM MIN_ROWS=10 MAX_ROWS=100 PACK_KEYS=1 DELAY_KEY_WRITE=1 ROW_FORMAT=fixed;
|
||||
show create table t1;
|
||||
|
|
98
mysql-test/r/sp-error.result
Normal file
98
mysql-test/r/sp-error.result
Normal 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
555
mysql-test/r/sp.result
Normal 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;
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
145
mysql-test/t/sp-error.test
Normal 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
640
mysql-test/t/sp.test
Normal 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;
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
36
netware/BUILD/compile-netware-src
Normal file
36
netware/BUILD/compile-netware-src
Normal 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
|
||||
|
|
@ -13,7 +13,7 @@ path=`dirname $0`
|
|||
suffix="standard"
|
||||
|
||||
extra_configs=" \
|
||||
--with-innodb
|
||||
--with-innodb \
|
||||
"
|
||||
|
||||
. $path/compile-netware-END
|
||||
|
|
2
netware/BUILD/knetware.imp
Normal file
2
netware/BUILD/knetware.imp
Normal file
|
@ -0,0 +1,2 @@
|
|||
kYieldIfTimeSliceUp
|
||||
|
|
@ -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=:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.%
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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= ¤t_thd->killed;
|
||||
volatile THD::killed_state *killed= ¤t_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= ¤t_thd->killed;
|
||||
bool not_killable;
|
||||
volatile THD::killed_state *killed= ¤t_thd->killed;
|
||||
THD::killed_state not_killable;
|
||||
DBUG_ENTER("merge_buffers");
|
||||
|
||||
statistic_increment(filesort_merge_passes, &LOCK_status);
|
||||
if (param->not_killable)
|
||||
{
|
||||
killed= ¬_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++)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
40
sql/item.cc
40
sql/item.cc
|
@ -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,
|
||||
|
|
53
sql/item.h
53
sql/item.h
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
23
sql/lex.h
23
sql/lex.h
|
@ -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)},
|
||||
|
|
|
@ -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);
|
||||
|
|
13
sql/log.cc
13
sql/log.cc
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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
450
sql/sp.cc
Normal 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
65
sql/sp.h
Normal 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
53
sql/sp_cache.cc
Normal 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
65
sql/sp_cache.h
Normal 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
645
sql/sp_head.cc
Normal 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
411
sql/sp_head.h
Normal 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
115
sql/sp_pcontext.cc
Normal 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
162
sql/sp_pcontext.h
Normal 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
95
sql/sp_rcontext.h
Normal 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_ */
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue