New error messages
Test of unsigned BIGINT values Fixes for queries-per-hour Cleanup of replication code (comments and portability fixes) Make most of the binary log code 4G clean Changed syntax for GRANT ... QUERIES PER HOUR
This commit is contained in:
parent
e2a5c3e4cd
commit
be46289855
279
Docs/manual.texi
279
Docs/manual.texi
@ -2965,7 +2965,7 @@ for the records to be deleted, and then use these values to construct
|
|||||||
the @code{DELETE} statement (@code{DELETE FROM ... WHERE ... IN (key1,
|
the @code{DELETE} statement (@code{DELETE FROM ... WHERE ... IN (key1,
|
||||||
key2, ...)}).
|
key2, ...)}).
|
||||||
|
|
||||||
The second option is to use interactive SQL to contruct a set of
|
The second option is to use interactive SQL to construct a set of
|
||||||
@code{DELETE} statements automatically, using the MySQL
|
@code{DELETE} statements automatically, using the MySQL
|
||||||
extension @code{CONCAT()} (in lieu of the standard @code{||} operator).
|
extension @code{CONCAT()} (in lieu of the standard @code{||} operator).
|
||||||
For example:
|
For example:
|
||||||
@ -3686,6 +3686,7 @@ For platform-specific bugs, see the sections about compiling and porting.
|
|||||||
|
|
||||||
@menu
|
@menu
|
||||||
* TODO MySQL 4.0:: Things That Should be in Version 4.0
|
* TODO MySQL 4.0:: Things That Should be in Version 4.0
|
||||||
|
* TODO MySQL 4.1::
|
||||||
* TODO future:: Things That Must be Done in the Near Future
|
* TODO future:: Things That Must be Done in the Near Future
|
||||||
* TODO sometime:: Things That Have to be Done Sometime
|
* TODO sometime:: Things That Have to be Done Sometime
|
||||||
* TODO unplanned:: Things we don't Have any Plans to do
|
* TODO unplanned:: Things we don't Have any Plans to do
|
||||||
@ -3702,30 +3703,30 @@ standard, but with a lot of useful extensions. The challenge is to do
|
|||||||
this without sacrifying the speed or compromise the code.
|
this without sacrifying the speed or compromise the code.
|
||||||
|
|
||||||
|
|
||||||
@node TODO MySQL 4.0, TODO future, TODO, TODO
|
@node TODO MySQL 4.0, TODO MySQL 4.1, TODO, TODO
|
||||||
@subsection Things That Should be in 4.0
|
@subsection Things That Should be in 4.0
|
||||||
|
|
||||||
We have now shifted development to MySQL Server 4.0. Most of the basic
|
We have now in the final stages one the development of the MySQL Server
|
||||||
things we want to have in 4.0 are already done. The target is to quickly
|
4.0. server. The target is to quickly implement the rest of the
|
||||||
implement the rest of the following features and then shift development
|
following features and then shift development to MySQL Server
|
||||||
to MySQL Server 4.1. @xref{MySQL 4.0 In A Nutshell}.
|
4.1. @xref{MySQL 4.0 In A Nutshell}.
|
||||||
|
|
||||||
The news section for 4.0 includes a list of the features we have already
|
The news section for 4.0 includes a list of the features we have already
|
||||||
implemented in the 4.0 tree. @xref{News-4.0.x}.
|
implemented in the 4.0 tree. @xref{News-4.0.x}.
|
||||||
|
|
||||||
This section lists features not yet implemented in the current
|
This section lists features not yet implemented in the current version
|
||||||
version of MySQL Server 4.0, which will however be implemented in
|
of MySQL Server 4.0, which will however be implemented in later versions
|
||||||
later versions of MySQL 4.0. This being very volatile information,
|
of MySQL 4.0. This being very volatile information, please consider this
|
||||||
please consider this list valid only if you are reading it from
|
list valid only if you are reading it from the MySQL web site
|
||||||
the MySQL web site (@uref{http://www.mysql.com/}).
|
(@uref{http://www.mysql.com/}).
|
||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
Allow users to change startup options without taking down the server.
|
Allow users to change startup options without taking down the server.
|
||||||
@item
|
@item
|
||||||
Fail safe replication.
|
Better command line argument handling.
|
||||||
@item
|
@item
|
||||||
New key cache
|
New key cache, which will give better performance when using many threads.
|
||||||
@item
|
@item
|
||||||
New table definition file format (@code{.frm} files) This will enable us
|
New table definition file format (@code{.frm} files) This will enable us
|
||||||
to not run out of bits when adding more table options. One will still
|
to not run out of bits when adding more table options. One will still
|
||||||
@ -3733,7 +3734,34 @@ be able to use the old @code{.frm} file format with 4.0. All newly created
|
|||||||
tables will, however, use the new format.
|
tables will, however, use the new format.
|
||||||
|
|
||||||
The new file format will enable us to add new column types, more options
|
The new file format will enable us to add new column types, more options
|
||||||
for keys and @code{FOREIGN KEY} support.
|
for keys and possible to store and retrieve @code{FOREIGN KEY} definitions.
|
||||||
|
@item
|
||||||
|
@code{SHOW COLUMNS FROM table_name} (used by @code{mysql} client to allow
|
||||||
|
expansions of column names) should not open the table, but only the
|
||||||
|
definition file. This will require less memory and be much faster.
|
||||||
|
@item
|
||||||
|
@code{SET SQL_DEFAULT_TABLE_TYPE=[MyISAM | INNODB | BDB | HEAP]}.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
|
||||||
|
@node TODO MySQL 4.1, TODO future, TODO MySQL 4.0, TODO
|
||||||
|
@subsection Things That Should be in 4.1
|
||||||
|
|
||||||
|
We will start working on MySQL 4.1 as soon as MySQL 4.0 goes into beta.
|
||||||
|
|
||||||
|
The following features is the ones we plan that should be in MySQL 4.1.
|
||||||
|
Note that because we have many developers that are working on different
|
||||||
|
projects, there will also be many additional features. There is also a
|
||||||
|
small change that some of these features will be added to MySQL 4.0.
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
Subqueries.
|
||||||
|
@code{SELECT id FROM t WHERE grp IN (SELECT grp FROM g WHERE u > 100)}
|
||||||
|
@item
|
||||||
|
Foreign keys, including cascading delete.
|
||||||
|
@item
|
||||||
|
Fail safe replication.
|
||||||
@item
|
@item
|
||||||
Replication should work with @code{RAND()} and user variables @code{@@var}.
|
Replication should work with @code{RAND()} and user variables @code{@@var}.
|
||||||
@item
|
@item
|
||||||
@ -3741,18 +3769,21 @@ Online backup with very low performance penalty. The online backup will
|
|||||||
make it easy to add a new replication slave without taking down the
|
make it easy to add a new replication slave without taking down the
|
||||||
master.
|
master.
|
||||||
@item
|
@item
|
||||||
|
Derived tables.
|
||||||
|
@example
|
||||||
|
SELECT a.col1, b.col2
|
||||||
|
FROM (SELECT MAX(col1) AS col1 FROM root_table) a,
|
||||||
|
other_table b
|
||||||
|
WHERE a.col1=b.col1;
|
||||||
|
@end example
|
||||||
|
|
||||||
|
This could be done by automatically creating temporary tables for the
|
||||||
|
derived tables for the duration of the query.
|
||||||
|
@item
|
||||||
Allow @code{DELETE} on @code{MyISAM} tables to use the record cache.
|
Allow @code{DELETE} on @code{MyISAM} tables to use the record cache.
|
||||||
To do this, we need to update the threads record cache when we update
|
To do this, we need to update the threads record cache when we update
|
||||||
the @code{.MYD} file.
|
the @code{.MYD} file.
|
||||||
@item
|
@item
|
||||||
Character set casts and syntax for handling multiple character sets.
|
|
||||||
@item
|
|
||||||
Help for all commands from the client.
|
|
||||||
@item
|
|
||||||
@code{SHOW COLUMNS FROM table_name} (used by @code{mysql} client to allow
|
|
||||||
expansions of column names) should not open the table, but only the
|
|
||||||
definition file. This will require less memory and be much faster.
|
|
||||||
@item
|
|
||||||
When using @code{SET CHARACTER SET} we should translate the whole query
|
When using @code{SET CHARACTER SET} we should translate the whole query
|
||||||
at once and not only strings. This will enable users to use the translated
|
at once and not only strings. This will enable users to use the translated
|
||||||
characters in database, table and column names.
|
characters in database, table and column names.
|
||||||
@ -3765,46 +3796,30 @@ of @code{analyze} is run on all sub tables.
|
|||||||
@code{RENAME TABLE} on a table used in an active @code{MERGE} table may
|
@code{RENAME TABLE} on a table used in an active @code{MERGE} table may
|
||||||
corrupt the table.
|
corrupt the table.
|
||||||
@item
|
@item
|
||||||
@code{SET SQL_DEFAULT_TABLE_TYPE=[MyISAM | INNODB | BDB | HEAP]}.
|
A faster, smaller embedded MySQL library. (Compatible with the old one)
|
||||||
@end itemize
|
|
||||||
|
|
||||||
|
|
||||||
@node TODO future, TODO sometime, TODO MySQL 4.0, TODO
|
|
||||||
@subsection Things That Must be Done in the Real Near Future
|
|
||||||
|
|
||||||
@itemize @bullet
|
|
||||||
@item
|
@item
|
||||||
Subqueries.
|
Stable openssl support. (MySQL 4.0 supports rudimentary, not 100 % tested
|
||||||
@code{SELECT id FROM t WHERE grp IN (SELECT grp FROM g WHERE u > 100)}
|
support for openssl).
|
||||||
@item
|
@item
|
||||||
Atomic multi-table updates, eg @code{update items,month set
|
Add support for sorting on @code{UNICODE}.
|
||||||
items.price=month.price where items.id=month.id;};
|
|
||||||
@item
|
@item
|
||||||
Derived tables.
|
Character set casts and syntax for handling multiple character sets.
|
||||||
@example
|
|
||||||
SELECT a.col1, b.col2
|
|
||||||
FROM (SELECT MAX(col1) AS col1 FROM root_table) a,
|
|
||||||
other_table b
|
|
||||||
WHERE a.col1=b.col1;
|
|
||||||
@end example
|
|
||||||
|
|
||||||
This could be done by automatically creating temporary tables for the
|
|
||||||
derived tables for the duration of the query.
|
|
||||||
@item
|
@item
|
||||||
Add @code{PREPARE} of statements and sending of parameters to @code{mysqld}.
|
When using @code{SET CHARACTER SET} we should translate the whole query
|
||||||
|
at once and not only strings. This will enable users to use the translated
|
||||||
|
characters in database, table and column names.
|
||||||
@item
|
@item
|
||||||
Extend the client/server protocol to support warnings.
|
Help for all commands from the client.
|
||||||
@item
|
@item
|
||||||
Add options to the client/server protocol to get progress notes
|
New faster client/server protocol which will support prepared statements,
|
||||||
for long running commands.
|
bound parameters and bound result columns, binary transfer of data,
|
||||||
|
warnings...
|
||||||
@item
|
@item
|
||||||
Add database and real table name (in case of alias) to the MYSQL_FIELD
|
Add database and real table name (in case of alias) to the MYSQL_FIELD
|
||||||
structure.
|
structure.
|
||||||
@item
|
@item
|
||||||
Don't allow more than a defined number of threads to run MyISAM recover
|
Add options to the client/server protocol to get progress notes
|
||||||
at the same time.
|
for long running commands.
|
||||||
@item
|
|
||||||
Change @code{INSERT ... SELECT} to optionally use concurrent inserts.
|
|
||||||
@item
|
@item
|
||||||
Implement @code{RENAME DATABASE}. To make this safe for all table handlers,
|
Implement @code{RENAME DATABASE}. To make this safe for all table handlers,
|
||||||
it should work as follows:
|
it should work as follows:
|
||||||
@ -3818,16 +3833,45 @@ we do with the @code{RENAME} command.
|
|||||||
Drop the old database.
|
Drop the old database.
|
||||||
@end itemize
|
@end itemize
|
||||||
@item
|
@item
|
||||||
|
Add true @code{VARCHAR} support (There is already support for this in
|
||||||
|
@code{MyISAM}).
|
||||||
|
@item
|
||||||
|
Optimise @code{BIT} type to take 1 bit (now @code{BIT} takes 1 char).
|
||||||
|
@item
|
||||||
|
New internal file interface change. This will make all file handling much
|
||||||
|
more general and make it easier to add extensions like RAID nicely.
|
||||||
|
(The current implementation is a hack).
|
||||||
|
@item
|
||||||
|
Better in-memory (@code{HEAP}) tables:
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
Support for B-tree indexes
|
||||||
|
@item
|
||||||
|
Dynamic size rows
|
||||||
|
@item
|
||||||
|
Faster row handling (less copying)
|
||||||
|
@end itemize
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
|
||||||
|
@node TODO future, TODO sometime, TODO MySQL 4.1, TODO
|
||||||
|
@subsection Things That Must be Done in the Real Near Future
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
Atomic multi-table updates, eg @code{update items,month set
|
||||||
|
items.price=month.price where items.id=month.id;};
|
||||||
|
@item
|
||||||
|
Don't allow more than a defined number of threads to run MyISAM recover
|
||||||
|
at the same time.
|
||||||
|
@item
|
||||||
|
Change @code{INSERT ... SELECT} to optionally use concurrent inserts.
|
||||||
|
@item
|
||||||
Return the original field types() when doing @code{SELECT MIN(column)
|
Return the original field types() when doing @code{SELECT MIN(column)
|
||||||
... GROUP BY}.
|
... GROUP BY}.
|
||||||
@item
|
@item
|
||||||
Multiple result sets.
|
Multiple result sets.
|
||||||
@item
|
@item
|
||||||
Change the protocol to allow binary transfer of values. To do this
|
|
||||||
efficiently, we need to add an API to allow binding of variables.
|
|
||||||
@item
|
|
||||||
Add @code{PREPARE} of statements and sending of parameters to @code{mysqld}.
|
|
||||||
@item
|
|
||||||
Make it possible to specify @code{long_query_time} with a granularity
|
Make it possible to specify @code{long_query_time} with a granularity
|
||||||
in microseconds.
|
in microseconds.
|
||||||
@item
|
@item
|
||||||
@ -3836,6 +3880,8 @@ options like database in use, time and date...
|
|||||||
@item
|
@item
|
||||||
Link the @code{myisampack} code into the server.
|
Link the @code{myisampack} code into the server.
|
||||||
@item
|
@item
|
||||||
|
Port of the MySQL code to QNX.
|
||||||
|
@item
|
||||||
Port of the MySQL code to BeOS.
|
Port of the MySQL code to BeOS.
|
||||||
@item
|
@item
|
||||||
Port of the MySQL clients to LynxOS.
|
Port of the MySQL clients to LynxOS.
|
||||||
@ -3864,10 +3910,6 @@ Allow join on key parts (optimisation issue).
|
|||||||
@code{INSERT SQL_CONCURRENT} and @code{mysqld --concurrent-insert} to do
|
@code{INSERT SQL_CONCURRENT} and @code{mysqld --concurrent-insert} to do
|
||||||
a concurrent insert at the end of the file if the file is read-locked.
|
a concurrent insert at the end of the file if the file is read-locked.
|
||||||
@item
|
@item
|
||||||
Remember @code{FOREIGN} key definitions in the @file{.frm} file.
|
|
||||||
@item
|
|
||||||
Cascading @code{DELETE}
|
|
||||||
@item
|
|
||||||
Server side cursors.
|
Server side cursors.
|
||||||
@item
|
@item
|
||||||
Check if @code{lockd} works with modern Linux kernels; If not, we have
|
Check if @code{lockd} works with modern Linux kernels; If not, we have
|
||||||
@ -3891,8 +3933,6 @@ an @code{INSERT} that doesn't contain a column that doesn't have a
|
|||||||
Fix @file{libmysql.c} to allow two @code{mysql_query()} commands in a row
|
Fix @file{libmysql.c} to allow two @code{mysql_query()} commands in a row
|
||||||
without reading results or give a nice error message when one does this.
|
without reading results or give a nice error message when one does this.
|
||||||
@item
|
@item
|
||||||
Optimise @code{BIT} type to take 1 bit (now @code{BIT} takes 1 char).
|
|
||||||
@item
|
|
||||||
Check why MIT-pthreads @code{ctime()} doesn't work on some FreeBSD systems.
|
Check why MIT-pthreads @code{ctime()} doesn't work on some FreeBSD systems.
|
||||||
@item
|
@item
|
||||||
Add an @code{IMAGE} option to @code{LOAD DATA INFILE} to not update
|
Add an @code{IMAGE} option to @code{LOAD DATA INFILE} to not update
|
||||||
@ -3933,15 +3973,10 @@ and maybe
|
|||||||
data_line - the line from the data file
|
data_line - the line from the data file
|
||||||
@end example
|
@end example
|
||||||
@item
|
@item
|
||||||
Add true @code{VARCHAR} support (There is already support for this in
|
|
||||||
@code{MyISAM}).
|
|
||||||
@item
|
|
||||||
Automatic output from @code{mysql} to Netscape.
|
Automatic output from @code{mysql} to Netscape.
|
||||||
@item
|
@item
|
||||||
@code{LOCK DATABASES}. (with various options)
|
@code{LOCK DATABASES}. (with various options)
|
||||||
@item
|
@item
|
||||||
Change sort to allocate memory in ``hunks'' to get better memory utilisation.
|
|
||||||
@item
|
|
||||||
@code{DECIMAL} and @code{NUMERIC} types can't read exponential numbers;
|
@code{DECIMAL} and @code{NUMERIC} types can't read exponential numbers;
|
||||||
@code{Field_decimal::store(const char *from,uint len)} must be recoded
|
@code{Field_decimal::store(const char *from,uint len)} must be recoded
|
||||||
to fix this.
|
to fix this.
|
||||||
@ -3965,8 +4000,6 @@ table. This would be a bit slow if you requested information about all tables,
|
|||||||
but very flexible. @code{SHOW INFO FROM tbl_name} for basic table information
|
but very flexible. @code{SHOW INFO FROM tbl_name} for basic table information
|
||||||
should be implemented.
|
should be implemented.
|
||||||
@item
|
@item
|
||||||
Add support for UNICODE.
|
|
||||||
@item
|
|
||||||
@code{NATURAL JOIN}.
|
@code{NATURAL JOIN}.
|
||||||
@item
|
@item
|
||||||
Allow @code{select a from crash_me left join crash_me2 using (a)}; In this
|
Allow @code{select a from crash_me left join crash_me2 using (a)}; In this
|
||||||
@ -4006,9 +4039,6 @@ Change that @code{ALTER TABLE} doesn't abort clients that executes
|
|||||||
Fix that when columns referenced in an @code{UPDATE} clause contains the old
|
Fix that when columns referenced in an @code{UPDATE} clause contains the old
|
||||||
values before the update started.
|
values before the update started.
|
||||||
@item
|
@item
|
||||||
@code{myisamchk}, @code{REPAIR} and @code{OPTIMIZE TABLE} should be able
|
|
||||||
to handle cases where the data and/or index files are symbolic links.
|
|
||||||
@item
|
|
||||||
Add simulation of @code{pread()}/@code{pwrite()} on Windows to enable
|
Add simulation of @code{pread()}/@code{pwrite()} on Windows to enable
|
||||||
concurrent inserts.
|
concurrent inserts.
|
||||||
@item
|
@item
|
||||||
@ -6436,7 +6466,7 @@ sometimes required. If you have problems, we recommend trying GNU
|
|||||||
If you are using a recent version of @strong{gcc}, recent enough to understand
|
If you are using a recent version of @strong{gcc}, recent enough to understand
|
||||||
@code{-fno-exceptions} option, it is @strong{very important} that you use
|
@code{-fno-exceptions} option, it is @strong{very important} that you use
|
||||||
it. Otherwise, you may compile a binary that crashes randomly. We also
|
it. Otherwise, you may compile a binary that crashes randomly. We also
|
||||||
recommend that you use @code{-felide-contructors} and @code{-fno-rtti} along
|
recommend that you use @code{-felide-constructors} and @code{-fno-rtti} along
|
||||||
with @code{-fno-exceptions}. When in doubt, do the following:
|
with @code{-fno-exceptions}. When in doubt, do the following:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
@ -6969,8 +6999,9 @@ speed of your connection; be patient.
|
|||||||
@item
|
@item
|
||||||
You will need GNU @code{autoconf 2.13}, @code{automake 1.4},
|
You will need GNU @code{autoconf 2.13}, @code{automake 1.4},
|
||||||
@code{libtool}, and @code{m4} to run the next set of commands.
|
@code{libtool}, and @code{m4} to run the next set of commands.
|
||||||
Note that the new versions of @code{autoconf} (2.52) and @code{automake}
|
|
||||||
(1.5) do not work.
|
If you are using the 3.23 tree the new versions of @code{autoconf}
|
||||||
|
(2.52) and @code{automake} (1.5) will not work.
|
||||||
|
|
||||||
If you get some strange error during this stage, check that you really
|
If you get some strange error during this stage, check that you really
|
||||||
have @code{libtool} installed!
|
have @code{libtool} installed!
|
||||||
@ -8100,12 +8131,24 @@ than it had in 3.23.
|
|||||||
@item
|
@item
|
||||||
@code{SIGNED} is a reserved word.
|
@code{SIGNED} is a reserved word.
|
||||||
@item
|
@item
|
||||||
|
The result of all bitwise operators @code{|}, @code{&}, @code{<<},
|
||||||
|
@code{>>} and @code{~} is now unsigned. This may cause problems if your
|
||||||
|
are using them in a context where you want an signed result. @xref{Cast
|
||||||
|
Functions}.
|
||||||
|
@item
|
||||||
|
@strong{NOTE:} When you use subtraction between integers values where
|
||||||
|
one is of type @code{UNSIGNED}, the result will be unsigned! In other
|
||||||
|
words, before upgrading to MySQL 4.0, you should check your application
|
||||||
|
for cases where you are subtracting a value from an unsigned entity
|
||||||
|
and want a negative answer or subtracting an unsigned value from a an
|
||||||
|
integer column. @xref{Cast Functions}.
|
||||||
|
@item
|
||||||
To use @code{MATCH ... AGAINST (... IN BOOLEAN MODE)} with your tables,
|
To use @code{MATCH ... AGAINST (... IN BOOLEAN MODE)} with your tables,
|
||||||
you need to rebuild them with @code{ALTER TABLE table_name TYPE=MyISAM},
|
you need to rebuild them with @code{ALTER TABLE table_name TYPE=MyISAM},
|
||||||
@strong{even} if they are of @code{MyISAM} type.
|
@strong{even} if they are of @code{MyISAM} type.
|
||||||
@item
|
@item
|
||||||
@code{LOCATE()} and @code{INSTR()} are case sensitive if neither
|
@code{LOCATE()} and @code{INSTR()} are case sensitive if one of the
|
||||||
argument is a binary string.
|
arguments is a binary string.
|
||||||
@item
|
@item
|
||||||
@code{HEX(string)} now returns the characters in string converted to
|
@code{HEX(string)} now returns the characters in string converted to
|
||||||
hexadecimal. If you want to convert a number to hexadecimal, you should
|
hexadecimal. If you want to convert a number to hexadecimal, you should
|
||||||
@ -16159,7 +16202,7 @@ GRANT priv_type [(column_list)] [, priv_type [(column_list)] ...]
|
|||||||
[CIPHER cipher [AND]]
|
[CIPHER cipher [AND]]
|
||||||
[ISSUER issuer [AND]]
|
[ISSUER issuer [AND]]
|
||||||
[SUBJECT subject]]
|
[SUBJECT subject]]
|
||||||
[WITH GRANT OPTION]
|
[WITH [GRANT OPTION | MAX_QUERIES_PER_HOUR=#]]
|
||||||
|
|
||||||
REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...]
|
REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...]
|
||||||
ON @{tbl_name | * | *.* | db_name.*@}
|
ON @{tbl_name | * | *.* | db_name.*@}
|
||||||
@ -16320,6 +16363,12 @@ to other users any privileges the user has at the specified privilege level.
|
|||||||
You should be careful to whom you give the @strong{grant} privilege, as two
|
You should be careful to whom you give the @strong{grant} privilege, as two
|
||||||
users with different privileges may be able to join privileges!
|
users with different privileges may be able to join privileges!
|
||||||
|
|
||||||
|
@code{MAX_QUERIES_PER_HOUR=#} limits the number of queries the user can
|
||||||
|
do during one hour. If @code{#} is 0, then this means that there is no
|
||||||
|
limit of the number of queries. This works by MySQL resetting a user
|
||||||
|
specific query counter to 0, after it has gone more than one hour
|
||||||
|
since the counter started incrementing.
|
||||||
|
|
||||||
You cannot grant another user a privilege you don't have yourself;
|
You cannot grant another user a privilege you don't have yourself;
|
||||||
the @strong{grant} privilege allows you to give away only those privileges
|
the @strong{grant} privilege allows you to give away only those privileges
|
||||||
you possess.
|
you possess.
|
||||||
@ -28068,6 +28117,10 @@ that are optional.
|
|||||||
Note that if you specify @code{ZEROFILL} for a column, MySQL will
|
Note that if you specify @code{ZEROFILL} for a column, MySQL will
|
||||||
automatically add the @code{UNSIGNED} attribute to the column.
|
automatically add the @code{UNSIGNED} attribute to the column.
|
||||||
|
|
||||||
|
@strong{Warning:} You should be aware that when you use subtraction
|
||||||
|
between integers values where one is of type @code{UNSIGNED}, the result
|
||||||
|
will be unsigned! @xref{Cast Functions}.
|
||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
@tindex TINYINT
|
@tindex TINYINT
|
||||||
@item TINYINT[(M)] [UNSIGNED] [ZEROFILL]
|
@item TINYINT[(M)] [UNSIGNED] [ZEROFILL]
|
||||||
@ -30841,9 +30894,13 @@ make string comparison even more flexible.
|
|||||||
@node Arithmetic functions, Mathematical functions, Numeric Functions, Numeric Functions
|
@node Arithmetic functions, Mathematical functions, Numeric Functions, Numeric Functions
|
||||||
@subsubsection Arithmetic Operations
|
@subsubsection Arithmetic Operations
|
||||||
|
|
||||||
|
@cindex operators, cast
|
||||||
The usual arithmetic operators are available. Note that in the case of
|
The usual arithmetic operators are available. Note that in the case of
|
||||||
@samp{-}, @samp{+}, and @samp{*}, the result is calculated with
|
@samp{-}, @samp{+}, and @samp{*}, the result is calculated with
|
||||||
@code{BIGINT} (64-bit) precision if both arguments are integers!
|
@code{BIGINT} (64-bit) precision if both arguments are integers!
|
||||||
|
If one of the argument is an unsigned integer, and the other argument
|
||||||
|
is also an integer, the result will be an unsigned integer.
|
||||||
|
@xref{Cast Functions}.
|
||||||
|
|
||||||
@cindex operations, arithmetic
|
@cindex operations, arithmetic
|
||||||
@cindex arithmetic expressions
|
@cindex arithmetic expressions
|
||||||
@ -30879,8 +30936,9 @@ mysql> select 18014398509481984*18014398509481984;
|
|||||||
-> 0
|
-> 0
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
The result of the last expression is incorrect because the result of the integer
|
The result of the last expression is incorrect because the result of the
|
||||||
multiplication exceeds the 64-bit range of @code{BIGINT} calculations.
|
integer multiplication exceeds the 64-bit range of @code{BIGINT}
|
||||||
|
calculations.
|
||||||
|
|
||||||
@findex / (division)
|
@findex / (division)
|
||||||
@findex division (/)
|
@findex division (/)
|
||||||
@ -31903,10 +31961,10 @@ mysql> select 1+'1';
|
|||||||
|
|
||||||
MySQL supports arithmetic with both signed and unsigned 64 bit values.
|
MySQL supports arithmetic with both signed and unsigned 64 bit values.
|
||||||
If you are using an numerical operations (like @code{+}) and one of the
|
If you are using an numerical operations (like @code{+}) and one of the
|
||||||
operands are @code{unsigned}, then the result will be unsigned. You can
|
operands are @code{unsigned integer}, then the result will be unsigned.
|
||||||
override this by using the @code{SIGNED} and @code{UNSIGNED} cast
|
You can override this by using the @code{SIGNED} and @code{UNSIGNED}
|
||||||
operators, which will cast the operation to signed respective unsigned
|
cast operators, which will cast the operation to signed respective
|
||||||
64 bit integer.
|
unsigned 64 bit integer.
|
||||||
|
|
||||||
@example
|
@example
|
||||||
mysql> select CAST(1-2 AS UNSIGNED)
|
mysql> select CAST(1-2 AS UNSIGNED)
|
||||||
@ -31915,8 +31973,33 @@ mysql select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED);
|
|||||||
-> -1
|
-> -1
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
Note that if either operation is a floating point value (In this context
|
||||||
|
@code{DECIMAL()} is regarded as a floating point value) the result will
|
||||||
|
be a floating point value and is not affected by the above rule.
|
||||||
|
|
||||||
|
@example
|
||||||
|
mysql> select CAST(1 AS UNSIGNED) -2.0
|
||||||
|
-> -1.0
|
||||||
|
@end example
|
||||||
|
|
||||||
|
If you are using a string in an arithmetic operation, this is converted
|
||||||
|
to a floating point number.
|
||||||
|
|
||||||
The @code{CAST()} and @code{CONVERT()} function was added in MySQL 4.0.2.
|
The @code{CAST()} and @code{CONVERT()} function was added in MySQL 4.0.2.
|
||||||
|
|
||||||
|
The handing of unsigned values was changed in MySQL 4.0 to be able to
|
||||||
|
support @code{BIGINT} values properly. If you have some code that you
|
||||||
|
want to run in both MySQL 4.0 and 3.23 (in which case you probably can't
|
||||||
|
use the CAST function), you can use the following trick to get a signed
|
||||||
|
result when subtracting two unsigned integer columns:
|
||||||
|
|
||||||
|
@example
|
||||||
|
SELECT (unsigned_column_1+0.0)-(unsigned_column_2+0.0);
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The idea is that the columns are converted to floating point before doing
|
||||||
|
the subtraction.
|
||||||
|
|
||||||
@node Other Functions, Group by functions, Cast Functions, Functions
|
@node Other Functions, Group by functions, Cast Functions, Functions
|
||||||
@subsection Other Functions
|
@subsection Other Functions
|
||||||
|
|
||||||
@ -31941,12 +32024,14 @@ these operators have a maximum range of 64 bits.
|
|||||||
@findex | (bitwise OR)
|
@findex | (bitwise OR)
|
||||||
@findex OR, bitwise
|
@findex OR, bitwise
|
||||||
@item |
|
@item |
|
||||||
Bitwise OR:
|
Bitwise OR
|
||||||
@example
|
@example
|
||||||
mysql> select 29 | 15;
|
mysql> select 29 | 15;
|
||||||
-> 31
|
-> 31
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
The result is an unsigned 64 bit integer.
|
||||||
|
|
||||||
@findex & (bitwise AND)
|
@findex & (bitwise AND)
|
||||||
@findex AND, bitwise
|
@findex AND, bitwise
|
||||||
@item &
|
@item &
|
||||||
@ -31956,6 +32041,8 @@ mysql> select 29 & 15;
|
|||||||
-> 13
|
-> 13
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
The result is an unsigned 64 bit integer.
|
||||||
|
|
||||||
@findex << (left shift)
|
@findex << (left shift)
|
||||||
@item <<
|
@item <<
|
||||||
Shifts a longlong (@code{BIGINT}) number to the left:
|
Shifts a longlong (@code{BIGINT}) number to the left:
|
||||||
@ -31964,6 +32051,8 @@ mysql> select 1 << 2;
|
|||||||
-> 4
|
-> 4
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
The result is an unsigned 64 bit integer.
|
||||||
|
|
||||||
@findex >> (right shift)
|
@findex >> (right shift)
|
||||||
@item >>
|
@item >>
|
||||||
Shifts a longlong (@code{BIGINT}) number to the right:
|
Shifts a longlong (@code{BIGINT}) number to the right:
|
||||||
@ -31972,6 +32061,8 @@ mysql> select 4 >> 2;
|
|||||||
-> 1
|
-> 1
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
The result is an unsigned 64 bit integer.
|
||||||
|
|
||||||
@findex ~
|
@findex ~
|
||||||
@item ~
|
@item ~
|
||||||
Invert all bits:
|
Invert all bits:
|
||||||
@ -31980,6 +32071,8 @@ mysql> select 5 & ~1;
|
|||||||
-> 4
|
-> 4
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
|
The result is an unsigned 64 bit integer.
|
||||||
|
|
||||||
@findex BIT_COUNT()
|
@findex BIT_COUNT()
|
||||||
@item BIT_COUNT(N)
|
@item BIT_COUNT(N)
|
||||||
Returns the number of bits that are set in the argument @code{N}:
|
Returns the number of bits that are set in the argument @code{N}:
|
||||||
@ -35091,6 +35184,7 @@ If MySQL encounters any errors in a multiple table rename, it
|
|||||||
will do a reverse rename for all renamed tables to get everything back
|
will do a reverse rename for all renamed tables to get everything back
|
||||||
to the original state.
|
to the original state.
|
||||||
|
|
||||||
|
@code{RENAME TABLE} was added in MySQL 3.23.23.
|
||||||
|
|
||||||
@node DROP TABLE, CREATE INDEX, RENAME TABLE, Data Definition
|
@node DROP TABLE, CREATE INDEX, RENAME TABLE, Data Definition
|
||||||
@subsection @code{DROP TABLE} Syntax
|
@subsection @code{DROP TABLE} Syntax
|
||||||
@ -48267,6 +48361,11 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
|
|||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
|
Added @code{WITH MAX_QUERIES_PER_HOUR=#} to @code{GRANT} command.
|
||||||
|
@item
|
||||||
|
The type returned for all bit functions (@code{|}, @code{<<} ...) are now of
|
||||||
|
type @code{unsigned integer}.
|
||||||
|
@item
|
||||||
Added detection if @code{nan} values in MyISAM to make it possible to
|
Added detection if @code{nan} values in MyISAM to make it possible to
|
||||||
repair tables with @code{nan} in float or double columns.
|
repair tables with @code{nan} in float or double columns.
|
||||||
@item
|
@item
|
||||||
@ -48377,8 +48476,8 @@ able to use boolean fulltext search}.
|
|||||||
@code{LOCATE()} and @code{INSTR()} are case sensitive if neither
|
@code{LOCATE()} and @code{INSTR()} are case sensitive if neither
|
||||||
argument is a binary string.
|
argument is a binary string.
|
||||||
@item
|
@item
|
||||||
Changed @code{RND()} initialization so that @code{RND(N)} and @code{RND(N+1)}
|
Changed @code{RAND()} initialization so that @code{RAND(N)} and
|
||||||
are more distinct.
|
@code{RAND(N+1)} are more distinct.
|
||||||
@item
|
@item
|
||||||
Fixed core dump bug in @code{UPDATE ... ORDER BY}.
|
Fixed core dump bug in @code{UPDATE ... ORDER BY}.
|
||||||
@item
|
@item
|
||||||
@ -48603,7 +48702,7 @@ not yet 100% confident in this code.
|
|||||||
@appendixsubsec Changes in release 3.23.47
|
@appendixsubsec Changes in release 3.23.47
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
Fixed in when using the following construct:
|
Fixed bug when using the following construct:
|
||||||
@code{SELECT ... WHERE key=@@var_name OR $key=@@var_name2}
|
@code{SELECT ... WHERE key=@@var_name OR $key=@@var_name2}
|
||||||
@item
|
@item
|
||||||
Restrict InnoDB keys to 500 bytes.
|
Restrict InnoDB keys to 500 bytes.
|
||||||
@ -50031,7 +50130,7 @@ that both non-threaded (@code{-lmysqlclient}) and threaded
|
|||||||
against a threaded @code{-lmysqlclient} will need to link against
|
against a threaded @code{-lmysqlclient} will need to link against
|
||||||
@code{libmysqlclient_r} now.
|
@code{libmysqlclient_r} now.
|
||||||
@item
|
@item
|
||||||
Added atomic @code{RENAME} command.
|
Added atomic @code{RENAME TABLE} command.
|
||||||
@item
|
@item
|
||||||
Don't count entries with @code{NULL} in @code{COUNT(DISTINCT ...)}.
|
Don't count entries with @code{NULL} in @code{COUNT(DISTINCT ...)}.
|
||||||
@item
|
@item
|
||||||
|
140
Docs/my_sys.txt
Normal file
140
Docs/my_sys.txt
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
Functions i mysys: (For flags se my_sys.h)
|
||||||
|
|
||||||
|
int my_copy _A((const char *from,const char *to,myf MyFlags));
|
||||||
|
- Copy file
|
||||||
|
|
||||||
|
int my_delete _A((const char *name,myf MyFlags));
|
||||||
|
- Delete file
|
||||||
|
|
||||||
|
int my_getwd _A((string buf,uint size,myf MyFlags));
|
||||||
|
int my_setwd _A((const char *dir,myf MyFlags));
|
||||||
|
- Get and set working directory
|
||||||
|
|
||||||
|
string my_tempnam _A((const char *pfx,myf MyFlags));
|
||||||
|
- Make a uniq temp file name by using dir and adding something after
|
||||||
|
pfx to make name uniq. Name is made by adding a uniq 6 length-string
|
||||||
|
and TMP_EXT after pfx.
|
||||||
|
Returns pointer to malloced area for filename. Should be freed by
|
||||||
|
free().
|
||||||
|
|
||||||
|
File my_open _A((const char *FileName,int Flags,myf MyFlags));
|
||||||
|
File my_create _A((const char *FileName,int CreateFlags,
|
||||||
|
int AccsesFlags, myf MyFlags));
|
||||||
|
int my_close _A((File Filedes,myf MyFlags));
|
||||||
|
uint my_read _A((File Filedes,byte *Buffer,uint Count,myf MyFlags));
|
||||||
|
uint my_write _A((File Filedes,const byte *Buffer,uint Count,
|
||||||
|
myf MyFlags));
|
||||||
|
ulong my_seek _A((File fd,ulong pos,int whence,myf MyFlags));
|
||||||
|
ulong my_tell _A((File fd,myf MyFlags));
|
||||||
|
- Use instead of open,open-with-create-flag, close read and write
|
||||||
|
to get automatic error-messages (flag: MYF_WME) and only have
|
||||||
|
to test for != 0 if error (flag: MY_NABP).
|
||||||
|
|
||||||
|
int my_rename _A((const char *from,const char *to,myf MyFlags));
|
||||||
|
- Rename file
|
||||||
|
|
||||||
|
FILE *my_fopen _A((const char *FileName,int Flags,myf MyFlags));
|
||||||
|
FILE *my_fdopen _A((File Filedes,int Flags,myf MyFlags));
|
||||||
|
int my_fclose _A((FILE *fd,myf MyFlags));
|
||||||
|
uint my_fread _A((FILE *stream,byte *Buffer,uint Count,myf MyFlags));
|
||||||
|
uint my_fwrite _A((FILE *stream,const byte *Buffer,uint Count,
|
||||||
|
myf MyFlags));
|
||||||
|
ulong my_fseek _A((FILE *stream,ulong pos,int whence,myf MyFlags));
|
||||||
|
ulong my_ftell _A((FILE *stream,myf MyFlags));
|
||||||
|
- Same read-interface for streams as for files
|
||||||
|
|
||||||
|
gptr _mymalloc _A((uint uSize,const char *sFile,
|
||||||
|
uint uLine, myf MyFlag));
|
||||||
|
gptr _myrealloc _A((string pPtr,uint uSize,const char *sFile,
|
||||||
|
uint uLine, myf MyFlag));
|
||||||
|
void _myfree _A((gptr pPtr,const char *sFile,uint uLine));
|
||||||
|
int _sanity _A((const char *sFile,unsigned int uLine));
|
||||||
|
gptr _myget_copy_of_memory _A((const byte *from,uint length,
|
||||||
|
const char *sFile, uint uLine,
|
||||||
|
myf MyFlag));
|
||||||
|
- malloc(size,myflag) is mapped to this functions if not compiled
|
||||||
|
with -DSAFEMALLOC
|
||||||
|
|
||||||
|
void TERMINATE _A((void));
|
||||||
|
- Writes malloc-info on stdout if compiled with -DSAFEMALLOC.
|
||||||
|
|
||||||
|
int my_chsize _A((File fd,ulong newlength,myf MyFlags));
|
||||||
|
- Change size of file
|
||||||
|
|
||||||
|
void my_error _D((int nr,myf MyFlags, ...));
|
||||||
|
- Writes message using error number (se mysys/errors.h) on
|
||||||
|
stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called.
|
||||||
|
|
||||||
|
void my_message _A((const char *str,myf MyFlags));
|
||||||
|
- Writes message-string on
|
||||||
|
stdout or curses if MYSYS_PROGRAM_USES_CURSES() is called.
|
||||||
|
|
||||||
|
void my_init _A((void ));
|
||||||
|
- Start each program (in main) with this.
|
||||||
|
void my_end _A((int infoflag));
|
||||||
|
- Gives info about program.
|
||||||
|
- If infoflag & MY_CHECK_ERROR prints if some files are left open
|
||||||
|
- If infoflag & MY_GIVE_INFO prints timing info and malloc info
|
||||||
|
about prog.
|
||||||
|
|
||||||
|
int my_redel _A((const char *from, const char *to, int MyFlags));
|
||||||
|
- Delete from before rename of to to from. Copyes state from old
|
||||||
|
file to new file. If MY_COPY_TIME is set sets old time.
|
||||||
|
|
||||||
|
int my_copystat _A((const char *from, const char *to, int MyFlags));
|
||||||
|
- Copye state from old file to new file.
|
||||||
|
If MY_COPY_TIME is set sets copy also time.
|
||||||
|
|
||||||
|
string my_filename _A((File fd));
|
||||||
|
- Give filename of open file.
|
||||||
|
|
||||||
|
int dirname _A((string to,const char *name));
|
||||||
|
- Copy name of directory from filename.
|
||||||
|
|
||||||
|
int test_if_hard_path _A((const char *dir_name));
|
||||||
|
- Test if dirname is a hard path (Starts from root)
|
||||||
|
|
||||||
|
void convert_dirname _A((string name));
|
||||||
|
- Convert dirname acording to system.
|
||||||
|
- In MSDOS changes all caracters to capitals and changes '/' to
|
||||||
|
'\'
|
||||||
|
string fn_ext _A((const char *name));
|
||||||
|
- Returns pointer to extension in filename
|
||||||
|
string fn_format _A((string to,const char *name,const char *dsk,
|
||||||
|
const char *form,int flag));
|
||||||
|
format a filename with replace of library and extension and
|
||||||
|
converts between different systems.
|
||||||
|
params to and name may be identicall
|
||||||
|
function dosn't change name if name != to
|
||||||
|
Flag may be: 1 force replace filnames library with 'dsk'
|
||||||
|
2 force replace extension with 'form' */
|
||||||
|
4 force Unpack filename (replace ~ with home)
|
||||||
|
8 Pack filename as short as possibly for output to
|
||||||
|
user.
|
||||||
|
All open requests should allways use at least:
|
||||||
|
"open(fn_format(temp_buffe,name,"","",4),...)" to unpack home and
|
||||||
|
convert filename to system-form.
|
||||||
|
|
||||||
|
string fn_same _A((string toname,const char *name,int flag));
|
||||||
|
- Copys directory and extension from name to toname if neaded.
|
||||||
|
copy can be forced by same flags that in fn_format.
|
||||||
|
|
||||||
|
int wild_compare _A((const char *str,const char *wildstr));
|
||||||
|
- Compare if str matches wildstr. Wildstr can contain "*" and "?"
|
||||||
|
as match-characters.
|
||||||
|
Returns 0 if match.
|
||||||
|
|
||||||
|
void get_date _A((string to,int timeflag));
|
||||||
|
- Get current date in a form ready for printing.
|
||||||
|
|
||||||
|
void soundex _A((string out_pntr, string in_pntr))
|
||||||
|
- Makes in_pntr to a 5 chars long string. All words that sounds
|
||||||
|
alike have the same string.
|
||||||
|
|
||||||
|
int init_key_cache _A((ulong use_mem,ulong leave_this_much_mem));
|
||||||
|
- Use cacheing of keys in MISAM, PISAM, and ISAM.
|
||||||
|
KEY_CACHE_SIZE is a good size.
|
||||||
|
- Remember to lock databases for optimal cacheing
|
||||||
|
|
||||||
|
void end_key_cache _A((void));
|
||||||
|
- End key-cacheing.
|
@ -453,3 +453,5 @@
|
|||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
#define ER_DUP_ARGUMENT 225
|
#define ER_DUP_ARGUMENT 225
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
#define ER_TOO_MANY_USER_CONNECTIONS 203
|
||||||
|
"User %-.64s has already more than 'max_user_connections' active connections",
|
||||||
|
@ -2276,9 +2276,9 @@ AC_OUTPUT(Makefile extra/Makefile mysys/Makefile isam/Makefile \
|
|||||||
include/mysql_version.h
|
include/mysql_version.h
|
||||||
, , [
|
, , [
|
||||||
test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
|
test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
|
||||||
rm -f $AVAILABLE_LANGUAGES_ERRORS_RULES
|
|
||||||
])
|
])
|
||||||
|
|
||||||
|
rm -f $AVAILABLE_LANGUAGES_ERRORS_RULES
|
||||||
echo
|
echo
|
||||||
echo "MySQL has a Web site at http://www.mysql.com/ which carries details on the"
|
echo "MySQL has a Web site at http://www.mysql.com/ which carries details on the"
|
||||||
echo "latest release, upcoming features, and other information to make your"
|
echo "latest release, upcoming features, and other information to make your"
|
||||||
@ -2288,6 +2288,6 @@ echo
|
|||||||
echo "Remember to check the platform specific part in the reference manual for"
|
echo "Remember to check the platform specific part in the reference manual for"
|
||||||
echo "hints about installing on your platfrom. See the Docs directory."
|
echo "hints about installing on your platfrom. See the Docs directory."
|
||||||
echo
|
echo
|
||||||
# This text is checked in ./Do-compile to se that the configure finished.
|
# The following text is checked in ./Do-compile to se that the configure ends.
|
||||||
echo "Thank you for choosing MySQL!"
|
echo "Thank you for choosing MySQL!"
|
||||||
echo
|
echo
|
||||||
|
@ -35,10 +35,10 @@ struct my_option
|
|||||||
enum get_opt_var_type var_type;
|
enum get_opt_var_type var_type;
|
||||||
enum get_opt_arg_type arg_type;
|
enum get_opt_arg_type arg_type;
|
||||||
int id; /* unique id or short option */
|
int id; /* unique id or short option */
|
||||||
long long def_value; /* Default value */
|
longlong def_value; /* Default value */
|
||||||
long long min_value; /* Min allowed value */
|
longlong min_value; /* Min allowed value */
|
||||||
long long max_value; /* Max allowed value */
|
longlong max_value; /* Max allowed value */
|
||||||
long long sub_size; /* Subtract this from given value */
|
longlong sub_size; /* Subtract this from given value */
|
||||||
long block_size; /* Value should be a mult. of this */
|
long block_size; /* Value should be a mult. of this */
|
||||||
int app_type; /* To be used by an application */
|
int app_type; /* To be used by an application */
|
||||||
my_bool changeable_var; /* If true, the option is a variable */
|
my_bool changeable_var; /* If true, the option is a variable */
|
||||||
|
@ -51,15 +51,16 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif /* _WIN32... */
|
#endif /* _WIN32... */
|
||||||
|
|
||||||
/* The macros below are borrowed from include/linux/compiler.h in the
|
/*
|
||||||
Linux kernel. Use them to indicate the likelyhood of the truthfulness
|
The macros below are borrowed from include/linux/compiler.h in the
|
||||||
of a condition. This serves two purposes - newer versions of gcc will be
|
Linux kernel. Use them to indicate the likelyhood of the truthfulness
|
||||||
able to optimize for branch predication, which could yield siginficant
|
of a condition. This serves two purposes - newer versions of gcc will be
|
||||||
performance gains in frequently executed sections of the code, and the
|
able to optimize for branch predication, which could yield siginficant
|
||||||
other reason to use them is for documentation
|
performance gains in frequently executed sections of the code, and the
|
||||||
|
other reason to use them is for documentation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if __GNUC__ == 2 && __GNUC_MINOR__ < 96
|
#if !defined(__GNUC__) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
|
||||||
#define __builtin_expect(x, expected_value) (x)
|
#define __builtin_expect(x, expected_value) (x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -242,4 +242,5 @@
|
|||||||
#define ER_CANT_UPDATE_WITH_READLOCK 1223
|
#define ER_CANT_UPDATE_WITH_READLOCK 1223
|
||||||
#define ER_MIXING_NOT_ALLOWED 1224
|
#define ER_MIXING_NOT_ALLOWED 1224
|
||||||
#define ER_DUP_ARGUMENT 1225
|
#define ER_DUP_ARGUMENT 1225
|
||||||
#define ER_ERROR_MESSAGES 226
|
#define ER_USER_LIMIT_REACHED 1226
|
||||||
|
#define ER_ERROR_MESSAGES 227
|
||||||
|
@ -64,3 +64,15 @@ CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER)
|
|||||||
select CONVERT('-1',UNSIGNED);
|
select CONVERT('-1',UNSIGNED);
|
||||||
CONVERT('-1',UNSIGNED)
|
CONVERT('-1',UNSIGNED)
|
||||||
18446744073709551615
|
18446744073709551615
|
||||||
|
select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1;
|
||||||
|
cast(-5 as unsigned) | 1 cast(-5 as unsigned) & -1
|
||||||
|
18446744073709551611 18446744073709551611
|
||||||
|
select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1;
|
||||||
|
cast(-5 as unsigned) -1 cast(-5 as unsigned) + 1
|
||||||
|
18446744073709551610 18446744073709551612
|
||||||
|
select ~5, cast(~5 as signed);
|
||||||
|
~5 cast(~5 as signed)
|
||||||
|
18446744073709551610 -6
|
||||||
|
select cast(5 as unsigned) -6.0;
|
||||||
|
cast(5 as unsigned) -6.0
|
||||||
|
-1.0
|
||||||
|
@ -6,4 +6,4 @@ select 1 | (1+1),5 & 3,bit_count(7) ;
|
|||||||
3 1 3
|
3 1 3
|
||||||
select 1 << 32,1 << 63, 1 << 64, 4 >> 2, 4 >> 63, 1<< 63 >> 60;
|
select 1 << 32,1 << 63, 1 << 64, 4 >> 2, 4 >> 63, 1<< 63 >> 60;
|
||||||
1 << 32 1 << 63 1 << 64 4 >> 2 4 >> 63 1<< 63 >> 60
|
1 << 32 1 << 63 1 << 64 4 >> 2 4 >> 63 1<< 63 >> 60
|
||||||
4294967296 -9223372036854775808 0 1 0 8
|
4294967296 9223372036854775808 0 1 0 8
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
select 0x41,0x41+0,0x41 | 0x7fffffffffffffff | 0,0xffffffffffffffff | 0 ;
|
select 0x41,0x41+0,0x41 | 0x7fffffffffffffff | 0,0xffffffffffffffff | 0 ;
|
||||||
0x41 0x41+0 0x41 | 0x7fffffffffffffff | 0 0xffffffffffffffff | 0
|
0x41 0x41+0 0x41 | 0x7fffffffffffffff | 0 0xffffffffffffffff | 0
|
||||||
A 65 9223372036854775807 -1
|
A 65 9223372036854775807 18446744073709551615
|
||||||
select 0x31+1,concat(0x31)+1,-0xf;
|
select 0x31+1,concat(0x31)+1,-0xf;
|
||||||
0x31+1 concat(0x31)+1 -0xf
|
0x31+1 concat(0x31)+1 -0xf
|
||||||
50 2 -15
|
50 2 -15
|
||||||
|
@ -33,3 +33,7 @@ drop table t1;
|
|||||||
select CAST(1-2 AS UNSIGNED);
|
select CAST(1-2 AS UNSIGNED);
|
||||||
select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER);
|
select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER);
|
||||||
select CONVERT('-1',UNSIGNED);
|
select CONVERT('-1',UNSIGNED);
|
||||||
|
select cast(-5 as unsigned) | 1, cast(-5 as unsigned) & -1;
|
||||||
|
select cast(-5 as unsigned) -1, cast(-5 as unsigned) + 1;
|
||||||
|
select ~5, cast(~5 as signed);
|
||||||
|
select cast(5 as unsigned) -6.0;
|
||||||
|
@ -180,15 +180,15 @@ class Item_num_op :public Item_func
|
|||||||
class Item_int_func :public Item_func
|
class Item_int_func :public Item_func
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Item_int_func() :Item_func() {}
|
Item_int_func() :Item_func() { max_length=21; }
|
||||||
Item_int_func(Item *a) :Item_func(a) {}
|
Item_int_func(Item *a) :Item_func(a) { max_length=21; }
|
||||||
Item_int_func(Item *a,Item *b) :Item_func(a,b) {}
|
Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length=21; }
|
||||||
Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) {}
|
Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { max_length=21; }
|
||||||
Item_int_func(List<Item> &list) :Item_func(list) {}
|
Item_int_func(List<Item> &list) :Item_func(list) { max_length=21; }
|
||||||
double val() { return (double) val_int(); }
|
double val() { return (double) val_int(); }
|
||||||
String *val_str(String*str);
|
String *val_str(String*str);
|
||||||
enum Item_result result_type () const { return INT_RESULT; }
|
enum Item_result result_type () const { return INT_RESULT; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=21; }
|
void fix_length_and_dec() {}
|
||||||
Field *tmp_table_field(TABLE *t_arg)
|
Field *tmp_table_field(TABLE *t_arg)
|
||||||
{
|
{
|
||||||
if (!t_arg) return result_field;
|
if (!t_arg) return result_field;
|
||||||
@ -203,7 +203,7 @@ public:
|
|||||||
double val() { return args[0]->val(); }
|
double val() { return args[0]->val(); }
|
||||||
longlong val_int() { return args[0]->val_int(); }
|
longlong val_int() { return args[0]->val_int(); }
|
||||||
void fix_length_and_dec()
|
void fix_length_and_dec()
|
||||||
{ decimals=0; max_length=args[0]->max_length; unsigned_flag=0; }
|
{ max_length=args[0]->max_length; unsigned_flag=0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_unsigned :public Item_int_func
|
class Item_func_unsigned :public Item_int_func
|
||||||
@ -213,7 +213,7 @@ public:
|
|||||||
double val() { return args[0]->val(); }
|
double val() { return args[0]->val(); }
|
||||||
longlong val_int() { return args[0]->val_int(); }
|
longlong val_int() { return args[0]->val_int(); }
|
||||||
void fix_length_and_dec()
|
void fix_length_and_dec()
|
||||||
{ decimals=0; max_length=args[0]->max_length; unsigned_flag=1; }
|
{ max_length=args[0]->max_length; unsigned_flag=1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -598,7 +598,6 @@ public:
|
|||||||
Item_func_ord(Item *a) :Item_int_func(a) {}
|
Item_func_ord(Item *a) :Item_int_func(a) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "ord"; }
|
const char *func_name() const { return "ord"; }
|
||||||
void fix_length_and_dec() { max_length=21; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_find_in_set :public Item_int_func
|
class Item_func_find_in_set :public Item_int_func
|
||||||
@ -620,7 +619,7 @@ public:
|
|||||||
Item_func_bit_or(Item *a,Item *b) :Item_int_func(a,b) {}
|
Item_func_bit_or(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "|"; }
|
const char *func_name() const { return "|"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=21; }
|
void fix_length_and_dec() { unsigned_flag=1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_bit_and :public Item_int_func
|
class Item_func_bit_and :public Item_int_func
|
||||||
@ -629,7 +628,7 @@ public:
|
|||||||
Item_func_bit_and(Item *a,Item *b) :Item_int_func(a,b) {}
|
Item_func_bit_and(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "&"; }
|
const char *func_name() const { return "&"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=21; }
|
void fix_length_and_dec() { unsigned_flag=1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_bit_count :public Item_int_func
|
class Item_func_bit_count :public Item_int_func
|
||||||
@ -638,7 +637,7 @@ public:
|
|||||||
Item_func_bit_count(Item *a) :Item_int_func(a) {}
|
Item_func_bit_count(Item *a) :Item_int_func(a) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "bit_count"; }
|
const char *func_name() const { return "bit_count"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=2; }
|
void fix_length_and_dec() { max_length=2; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_shift_left :public Item_int_func
|
class Item_func_shift_left :public Item_int_func
|
||||||
@ -647,7 +646,7 @@ public:
|
|||||||
Item_func_shift_left(Item *a,Item *b) :Item_int_func(a,b) {}
|
Item_func_shift_left(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "<<"; }
|
const char *func_name() const { return "<<"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=21; }
|
void fix_length_and_dec() { unsigned_flag=1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_shift_right :public Item_int_func
|
class Item_func_shift_right :public Item_int_func
|
||||||
@ -656,7 +655,6 @@ public:
|
|||||||
Item_func_shift_right(Item *a,Item *b) :Item_int_func(a,b) {}
|
Item_func_shift_right(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return ">>"; }
|
const char *func_name() const { return ">>"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=21; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_bit_neg :public Item_int_func
|
class Item_func_bit_neg :public Item_int_func
|
||||||
@ -665,7 +663,7 @@ public:
|
|||||||
Item_func_bit_neg(Item *a) :Item_int_func(a) {}
|
Item_func_bit_neg(Item *a) :Item_int_func(a) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "~"; }
|
const char *func_name() const { return "~"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=21; }
|
void fix_length_and_dec() { unsigned_flag=1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_set_last_insert_id :public Item_int_func
|
class Item_func_set_last_insert_id :public Item_int_func
|
||||||
@ -674,7 +672,7 @@ public:
|
|||||||
Item_func_set_last_insert_id(Item *a) :Item_int_func(a) {}
|
Item_func_set_last_insert_id(Item *a) :Item_int_func(a) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "last_insert_id"; }
|
const char *func_name() const { return "last_insert_id"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=args[0]->max_length; }
|
void fix_length_and_dec() { max_length=args[0]->max_length; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_benchmark :public Item_int_func
|
class Item_func_benchmark :public Item_int_func
|
||||||
@ -686,7 +684,7 @@ class Item_func_benchmark :public Item_int_func
|
|||||||
{}
|
{}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "benchmark"; }
|
const char *func_name() const { return "benchmark"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=0; }
|
void fix_length_and_dec() { max_length=1; maybe_null=0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -818,7 +816,7 @@ class Item_func_get_lock :public Item_int_func
|
|||||||
Item_func_get_lock(Item *a,Item *b) :Item_int_func(a,b) {}
|
Item_func_get_lock(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "get_lock"; }
|
const char *func_name() const { return "get_lock"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;}
|
void fix_length_and_dec() { max_length=1; maybe_null=1;}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_release_lock :public Item_int_func
|
class Item_func_release_lock :public Item_int_func
|
||||||
@ -828,7 +826,7 @@ class Item_func_release_lock :public Item_int_func
|
|||||||
Item_func_release_lock(Item *a) :Item_int_func(a) {}
|
Item_func_release_lock(Item *a) :Item_int_func(a) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "release_lock"; }
|
const char *func_name() const { return "release_lock"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;}
|
void fix_length_and_dec() { max_length=1; maybe_null=1;}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* replication functions */
|
/* replication functions */
|
||||||
@ -840,7 +838,7 @@ class Item_master_pos_wait :public Item_int_func
|
|||||||
Item_master_pos_wait(Item *a,Item *b) :Item_int_func(a,b) {}
|
Item_master_pos_wait(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
const char *func_name() const { return "master_pos_wait"; }
|
const char *func_name() const { return "master_pos_wait"; }
|
||||||
void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;}
|
void fix_length_and_dec() { max_length=1; maybe_null=1;}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -431,10 +431,11 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
|
|||||||
if (table->in_use == thd)
|
if (table->in_use == thd)
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
/* Create a table entry with the right key and with an old refresh version */
|
/*
|
||||||
/* Note that we must use my_malloc() here as this is freed by the table
|
Create a table entry with the right key and with an old refresh version
|
||||||
cache */
|
Note that we must use my_malloc() here as this is freed by the table
|
||||||
|
cache
|
||||||
|
*/
|
||||||
if (!(table= (TABLE*) my_malloc(sizeof(*table)+key_length,
|
if (!(table= (TABLE*) my_malloc(sizeof(*table)+key_length,
|
||||||
MYF(MY_WME | MY_ZEROFILL))))
|
MYF(MY_WME | MY_ZEROFILL))))
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
|
49
sql/log.cc
49
sql/log.cc
@ -370,6 +370,7 @@ err:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int MYSQL_LOG::reset_logs(THD* thd)
|
int MYSQL_LOG::reset_logs(THD* thd)
|
||||||
{
|
{
|
||||||
LOG_INFO linfo;
|
LOG_INFO linfo;
|
||||||
@ -403,6 +404,7 @@ err:
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
|
int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
|
||||||
{
|
{
|
||||||
// pre-conditions
|
// pre-conditions
|
||||||
@ -410,17 +412,17 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
|
|||||||
DBUG_ASSERT(index_file >= 0);
|
DBUG_ASSERT(index_file >= 0);
|
||||||
DBUG_ASSERT(rli->slave_running == 1);
|
DBUG_ASSERT(rli->slave_running == 1);
|
||||||
DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->relay_log_name));
|
DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->relay_log_name));
|
||||||
// assume that we have previously read the first log and
|
/*
|
||||||
// stored it in rli->relay_log_name
|
Assume that we have previously read the first log and
|
||||||
|
stored it in rli->relay_log_name
|
||||||
|
*/
|
||||||
DBUG_ASSERT(rli->linfo.index_file_offset ==
|
DBUG_ASSERT(rli->linfo.index_file_offset ==
|
||||||
strlen(rli->relay_log_name) + 1);
|
strlen(rli->relay_log_name) + 1);
|
||||||
|
|
||||||
int tmp_fd;
|
int tmp_fd;
|
||||||
|
|
||||||
|
|
||||||
char* fname, *io_buf;
|
char* fname, *io_buf;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
if (!(fname = (char*)my_malloc(IO_SIZE+FN_REFLEN, MYF(MY_WME))))
|
|
||||||
|
if (!(fname= (char*) my_malloc(IO_SIZE+FN_REFLEN, MYF(MY_WME))))
|
||||||
return 1;
|
return 1;
|
||||||
pthread_mutex_lock(&LOCK_index);
|
pthread_mutex_lock(&LOCK_index);
|
||||||
my_seek(index_file,rli->linfo.index_file_offset,
|
my_seek(index_file,rli->linfo.index_file_offset,
|
||||||
@ -436,21 +438,22 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
int bytes_read;
|
int bytes_read;
|
||||||
bytes_read = my_read(index_file, io_buf, IO_SIZE, MYF(0));
|
bytes_read = my_read(index_file, (byte*) io_buf, IO_SIZE, MYF(0));
|
||||||
if (bytes_read < 0) // error
|
if (bytes_read < 0) // error
|
||||||
{
|
{
|
||||||
error=1;
|
error=1;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (!bytes_read)
|
if (!bytes_read)
|
||||||
break; // end of file
|
break; // end of file
|
||||||
// otherwise, we've read something and need to write it out
|
// otherwise, we've read something and need to write it out
|
||||||
if (my_write(tmp_fd, io_buf, bytes_read, MYF(MY_WME|MY_NABP)))
|
if (my_write(tmp_fd, (byte*) io_buf, bytes_read, MYF(MY_WME|MY_NABP)))
|
||||||
{
|
{
|
||||||
error=1;
|
error=1;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err:
|
err:
|
||||||
if (tmp_fd)
|
if (tmp_fd)
|
||||||
my_close(tmp_fd, MYF(MY_WME));
|
my_close(tmp_fd, MYF(MY_WME));
|
||||||
@ -476,18 +479,20 @@ err:
|
|||||||
strnmov(rli->relay_log_name,rli->linfo.log_file_name,
|
strnmov(rli->relay_log_name,rli->linfo.log_file_name,
|
||||||
sizeof(rli->relay_log_name));
|
sizeof(rli->relay_log_name));
|
||||||
}
|
}
|
||||||
// no need to free io_buf because we allocated both fname and io_buf in
|
/*
|
||||||
// one malloc()
|
No need to free io_buf because we allocated both fname and io_buf in
|
||||||
|
one malloc()
|
||||||
|
*/
|
||||||
|
|
||||||
err2:
|
err2:
|
||||||
pthread_mutex_unlock(&LOCK_index);
|
pthread_mutex_unlock(&LOCK_index);
|
||||||
my_free(fname, MYF(MY_WME));
|
my_free(fname, MYF(MY_WME));
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
|
int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
|
||||||
{
|
{
|
||||||
if (index_file < 0) return LOG_INFO_INVALID;
|
|
||||||
if (no_rotate) return LOG_INFO_PURGE_NO_ROTATE;
|
|
||||||
int error;
|
int error;
|
||||||
char fname[FN_REFLEN];
|
char fname[FN_REFLEN];
|
||||||
char *p;
|
char *p;
|
||||||
@ -498,6 +503,10 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
|
|||||||
LINT_INIT(purge_offset);
|
LINT_INIT(purge_offset);
|
||||||
IO_CACHE io_cache;
|
IO_CACHE io_cache;
|
||||||
|
|
||||||
|
if (index_file < 0)
|
||||||
|
return LOG_INFO_INVALID;
|
||||||
|
if (no_rotate)
|
||||||
|
return LOG_INFO_PURGE_NO_ROTATE;
|
||||||
pthread_mutex_lock(&LOCK_index);
|
pthread_mutex_lock(&LOCK_index);
|
||||||
|
|
||||||
if (init_io_cache(&io_cache,index_file, IO_SIZE*2, READ_CACHE, (my_off_t) 0,
|
if (init_io_cache(&io_cache,index_file, IO_SIZE*2, READ_CACHE, (my_off_t) 0,
|
||||||
@ -569,9 +578,10 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
|
|||||||
sql_print_error("Error deleting %s during purge", l);
|
sql_print_error("Error deleting %s during purge", l);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we get killed -9 here, the sysadmin would have to do a small
|
/*
|
||||||
// vi job on the log index file after restart - otherwise, this should
|
If we get killed -9 here, the sysadmin would have to edit
|
||||||
// be safe
|
the log index file after restart - otherwise, this should be safe
|
||||||
|
*/
|
||||||
#ifdef HAVE_FTRUNCATE
|
#ifdef HAVE_FTRUNCATE
|
||||||
if (ftruncate(index_file,0))
|
if (ftruncate(index_file,0))
|
||||||
{
|
{
|
||||||
@ -737,14 +747,14 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
|
|||||||
pthread_mutex_lock(&LOCK_log);
|
pthread_mutex_lock(&LOCK_log);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (my_b_append(&log_file,buf,len))
|
if (my_b_append(&log_file,(byte*) buf,len))
|
||||||
{
|
{
|
||||||
error = 1;
|
error = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
|
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
|
||||||
|
|
||||||
if ((uint)my_b_append_tell(&log_file) > max_binlog_size)
|
if ((uint) my_b_append_tell(&log_file) > max_binlog_size)
|
||||||
{
|
{
|
||||||
new_file(1);
|
new_file(1);
|
||||||
}
|
}
|
||||||
@ -755,6 +765,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
|
bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
|
||||||
const char *format,...)
|
const char *format,...)
|
||||||
{
|
{
|
||||||
|
@ -26,17 +26,19 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
inline int my_b_safe_write(IO_CACHE* file, const char* buf,
|
inline int my_b_safe_write(IO_CACHE* file, const byte *buf,
|
||||||
int len)
|
int len)
|
||||||
{
|
{
|
||||||
// Sasha: We are not writing this with the ? operator to avoid hitting
|
/*
|
||||||
// a possible compiler bug. At least gcc 2.95 cannot deal with
|
Sasha: We are not writing this with the ? operator to avoid hitting
|
||||||
// several layers of ternary operators that evaluated comma(,) operator
|
a possible compiler bug. At least gcc 2.95 cannot deal with
|
||||||
// expressions inside - I do have a test case if somebody wants it
|
several layers of ternary operators that evaluated comma(,) operator
|
||||||
|
expressions inside - I do have a test case if somebody wants it
|
||||||
|
*/
|
||||||
if (file->type == SEQ_READ_APPEND)
|
if (file->type == SEQ_READ_APPEND)
|
||||||
return my_b_append(file,buf,len);
|
return my_b_append(file, buf,len);
|
||||||
return my_b_write(file,buf,len);
|
return my_b_write(file, buf,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MYSQL_CLIENT
|
#ifdef MYSQL_CLIENT
|
||||||
static void pretty_print_str(FILE* file, char* str, int len)
|
static void pretty_print_str(FILE* file, char* str, int len)
|
||||||
@ -94,6 +96,7 @@ static void pretty_print_str(String* packet, char* str, int len)
|
|||||||
packet->append('\'');
|
packet->append('\'');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline char* slave_load_file_stem(char*buf, uint file_id,
|
static inline char* slave_load_file_stem(char*buf, uint file_id,
|
||||||
int event_server_id)
|
int event_server_id)
|
||||||
{
|
{
|
||||||
@ -382,9 +385,9 @@ int Log_event::net_send(THD* thd, const char* log_name, my_off_t pos)
|
|||||||
event_type = get_type_str();
|
event_type = get_type_str();
|
||||||
net_store_data(packet, event_type, strlen(event_type));
|
net_store_data(packet, event_type, strlen(event_type));
|
||||||
net_store_data(packet, server_id);
|
net_store_data(packet, server_id);
|
||||||
net_store_data(packet, log_pos);
|
net_store_data(packet, (longlong) log_pos);
|
||||||
pack_info(packet);
|
pack_info(packet);
|
||||||
return my_net_write(&thd->net, (char*)packet->ptr(), packet->length());
|
return my_net_write(&thd->net, (char*) packet->ptr(), packet->length());
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -1218,31 +1221,30 @@ void Load_log_event::set_fields(List<Item> &fields)
|
|||||||
{
|
{
|
||||||
uint i;
|
uint i;
|
||||||
const char* field = this->fields;
|
const char* field = this->fields;
|
||||||
for(i = 0; i < num_fields; i++)
|
for (i = 0; i < num_fields; i++)
|
||||||
{
|
{
|
||||||
fields.push_back(new Item_field(db, table_name, field));
|
fields.push_back(new Item_field(db, table_name, field));
|
||||||
field += field_lens[i] + 1;
|
field += field_lens[i] + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Slave_log_event::Slave_log_event(THD* thd_arg,
|
Slave_log_event::Slave_log_event(THD* thd_arg,
|
||||||
struct st_relay_log_info* rli):
|
struct st_relay_log_info* rli):
|
||||||
Log_event(thd_arg),mem_pool(0),master_host(0)
|
Log_event(thd_arg),mem_pool(0),master_host(0)
|
||||||
{
|
{
|
||||||
if(!rli->inited)
|
if (!rli->inited)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MASTER_INFO* mi = rli->mi;
|
MASTER_INFO* mi = rli->mi;
|
||||||
// TODO: re-write this better without holding both
|
// TODO: re-write this better without holding both locks at the same time
|
||||||
// locks at the same time
|
|
||||||
pthread_mutex_lock(&mi->data_lock);
|
pthread_mutex_lock(&mi->data_lock);
|
||||||
pthread_mutex_lock(&rli->data_lock);
|
pthread_mutex_lock(&rli->data_lock);
|
||||||
master_host_len = strlen(mi->host);
|
master_host_len = strlen(mi->host);
|
||||||
master_log_len = strlen(rli->master_log_name);
|
master_log_len = strlen(rli->master_log_name);
|
||||||
// on OOM, just do not initialize the structure and print the error
|
// on OOM, just do not initialize the structure and print the error
|
||||||
if((mem_pool = (char*)my_malloc(get_data_size() + 1,
|
if ((mem_pool = (char*)my_malloc(get_data_size() + 1,
|
||||||
MYF(MY_WME))))
|
MYF(MY_WME))))
|
||||||
{
|
{
|
||||||
master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
|
master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
|
||||||
memcpy(master_host, mi->host, master_host_len + 1);
|
memcpy(master_host, mi->host, master_host_len + 1);
|
||||||
@ -1276,8 +1278,8 @@ void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
|
|||||||
print_header(file);
|
print_header(file);
|
||||||
fputc('\n', file);
|
fputc('\n', file);
|
||||||
fprintf(file, "Slave: master_host='%s' master_port=%d \
|
fprintf(file, "Slave: master_host='%s' master_port=%d \
|
||||||
master_log=%s master_pos=%s\n", master_host, master_port, master_log,
|
master_log=%s master_pos=%s\n",
|
||||||
llstr(master_pos, llbuff));
|
master_host, master_port, master_log, llstr(master_pos, llbuff));
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -1753,11 +1755,13 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli)
|
|||||||
close_temporary_tables(thd);
|
close_temporary_tables(thd);
|
||||||
cleanup_load_tmpdir();
|
cleanup_load_tmpdir();
|
||||||
}
|
}
|
||||||
// we do not want to update master_log pos because we get a rotate event
|
/*
|
||||||
// before stop, so by now master_log_name is set to the next log
|
We do not want to update master_log pos because we get a rotate event
|
||||||
// if we updated it, we will have incorrect master coordinates and this
|
before stop, so by now master_log_name is set to the next log
|
||||||
// could give false triggers in MASTER_POS_WAIT() that we have reached
|
if we updated it, we will have incorrect master coordinates and this
|
||||||
// the targed position when in fact we have not
|
could give false triggers in MASTER_POS_WAIT() that we have reached
|
||||||
|
the targed position when in fact we have not
|
||||||
|
*/
|
||||||
rli->inc_pos(get_event_len(), 0);
|
rli->inc_pos(get_event_len(), 0);
|
||||||
flush_relay_log_info(rli);
|
flush_relay_log_info(rli);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -214,7 +214,7 @@ public:
|
|||||||
time_t when;
|
time_t when;
|
||||||
ulong exec_time;
|
ulong exec_time;
|
||||||
uint32 server_id;
|
uint32 server_id;
|
||||||
uint32 log_pos;
|
my_off_t log_pos;
|
||||||
uint16 flags;
|
uint16 flags;
|
||||||
int cached_event_len;
|
int cached_event_len;
|
||||||
char* temp_buf;
|
char* temp_buf;
|
||||||
@ -351,12 +351,12 @@ protected:
|
|||||||
char* mem_pool;
|
char* mem_pool;
|
||||||
void init_from_mem_pool(int data_size);
|
void init_from_mem_pool(int data_size);
|
||||||
public:
|
public:
|
||||||
|
my_off_t master_pos;
|
||||||
char* master_host;
|
char* master_host;
|
||||||
int master_host_len;
|
|
||||||
uint16 master_port;
|
|
||||||
char* master_log;
|
char* master_log;
|
||||||
|
int master_host_len;
|
||||||
int master_log_len;
|
int master_log_len;
|
||||||
ulonglong master_pos;
|
uint16 master_port;
|
||||||
|
|
||||||
#ifndef MYSQL_CLIENT
|
#ifndef MYSQL_CLIENT
|
||||||
Slave_log_event(THD* thd_arg, struct st_relay_log_info* rli);
|
Slave_log_event(THD* thd_arg, struct st_relay_log_info* rli);
|
||||||
|
@ -399,7 +399,7 @@ max_allowed_packet on this server");
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char * mc_mysql_error(MYSQL *mysql)
|
char *mc_mysql_error(MYSQL *mysql)
|
||||||
{
|
{
|
||||||
return (mysql)->net.last_error;
|
return (mysql)->net.last_error;
|
||||||
}
|
}
|
||||||
@ -897,7 +897,7 @@ mc_mysql_close(MYSQL *mysql)
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mc_mysql_free_result(MYSQL_RES *result)
|
void mc_mysql_free_result(MYSQL_RES *result)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("mc_mysql_free_result");
|
DBUG_ENTER("mc_mysql_free_result");
|
||||||
DBUG_PRINT("enter",("mysql_res: %lx",result));
|
DBUG_PRINT("enter",("mysql_res: %lx",result));
|
||||||
@ -1280,17 +1280,17 @@ static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
my_ulonglong mc_mysql_num_rows(MYSQL_RES *res)
|
my_ulonglong mc_mysql_num_rows(MYSQL_RES *res)
|
||||||
{
|
{
|
||||||
return res->row_count;
|
return res->row_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int mc_mysql_num_fields(MYSQL_RES *res)
|
unsigned int mc_mysql_num_fields(MYSQL_RES *res)
|
||||||
{
|
{
|
||||||
return res->field_count;
|
return res->field_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
|
void mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
|
||||||
{
|
{
|
||||||
MYSQL_ROWS *tmp=0;
|
MYSQL_ROWS *tmp=0;
|
||||||
DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
|
DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row));
|
||||||
@ -1300,7 +1300,7 @@ void mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row)
|
|||||||
result->data_cursor = tmp;
|
result->data_cursor = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
MYSQL_ROW mc_mysql_fetch_row(MYSQL_RES *res)
|
MYSQL_ROW STDCALL mc_mysql_fetch_row(MYSQL_RES *res)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("mc_mysql_fetch_row");
|
DBUG_ENTER("mc_mysql_fetch_row");
|
||||||
if (!res->data)
|
if (!res->data)
|
||||||
@ -1335,7 +1335,7 @@ MYSQL_ROW mc_mysql_fetch_row(MYSQL_RES *res)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int mc_mysql_select_db(MYSQL *mysql, const char *db)
|
int mc_mysql_select_db(MYSQL *mysql, const char *db)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
DBUG_ENTER("mysql_select_db");
|
DBUG_ENTER("mysql_select_db");
|
||||||
|
@ -1950,8 +1950,7 @@ The server will not act as a slave.");
|
|||||||
}
|
}
|
||||||
if (!opt_noacl)
|
if (!opt_noacl)
|
||||||
(void) grant_init();
|
(void) grant_init();
|
||||||
if (max_user_connections || mqh_used)
|
init_max_user_conn();
|
||||||
init_max_user_conn();
|
|
||||||
|
|
||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
if (!opt_noacl)
|
if (!opt_noacl)
|
||||||
|
@ -201,7 +201,7 @@ void end_slave_list()
|
|||||||
|
|
||||||
static int find_target_pos(LEX_MASTER_INFO* mi, IO_CACHE* log, char* errmsg)
|
static int find_target_pos(LEX_MASTER_INFO* mi, IO_CACHE* log, char* errmsg)
|
||||||
{
|
{
|
||||||
uint32 log_pos = mi->pos;
|
uint32 log_pos = (uint32) mi->pos;
|
||||||
uint32 target_server_id = mi->server_id;
|
uint32 target_server_id = mi->server_id;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
@ -799,8 +799,7 @@ int load_master_data(THD* thd)
|
|||||||
{
|
{
|
||||||
strmake(active_mi->master_log_name, row[0],
|
strmake(active_mi->master_log_name, row[0],
|
||||||
sizeof(active_mi->master_log_name));
|
sizeof(active_mi->master_log_name));
|
||||||
// atoi() is ok, since offset is <= 1GB
|
active_mi->master_log_pos = strtoull(row[1], (char**) 0, 10);
|
||||||
active_mi->master_log_pos = atoi(row[1]);
|
|
||||||
if (active_mi->master_log_pos < 4)
|
if (active_mi->master_log_pos < 4)
|
||||||
active_mi->master_log_pos = 4; // don't hit the magic number
|
active_mi->master_log_pos = 4; // don't hit the magic number
|
||||||
active_mi->rli.pending = 0;
|
active_mi->rli.pending = 0;
|
||||||
|
@ -236,3 +236,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -230,3 +230,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -233,3 +233,4 @@
|
|||||||
"Kan de query niet uitvoeren vanwege een conflicterende read lock",
|
"Kan de query niet uitvoeren vanwege een conflicterende read lock",
|
||||||
"Het combineren van transactionele en niet-transactionele tabellen is uitgeschakeld.",
|
"Het combineren van transactionele en niet-transactionele tabellen is uitgeschakeld.",
|
||||||
"Optie '%s' tweemaal gebruikt in opdracht",
|
"Optie '%s' tweemaal gebruikt in opdracht",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -227,3 +227,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -232,3 +232,4 @@
|
|||||||
"Ei suuda täita päringut konfliktse luku tõttu",
|
"Ei suuda täita päringut konfliktse luku tõttu",
|
||||||
"Transaktsioone toetavate ning mittetoetavate tabelite kooskasutamine ei ole lubatud",
|
"Transaktsioone toetavate ning mittetoetavate tabelite kooskasutamine ei ole lubatud",
|
||||||
"Määrangut '%s' on lauses kasutatud topelt",
|
"Määrangut '%s' on lauses kasutatud topelt",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -227,3 +227,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -230,3 +230,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -227,3 +227,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -229,3 +229,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -227,3 +227,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -229,3 +229,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -227,3 +227,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -229,3 +229,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -229,3 +229,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -231,3 +231,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -227,3 +227,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -231,3 +231,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -230,3 +230,4 @@
|
|||||||
"Невозможно выполнить запрос из-за конфликтной блокировки чтения",
|
"Невозможно выполнить запрос из-за конфликтной блокировки чтения",
|
||||||
"Одновременное использование transactional и non-transactional таблиц отключено",
|
"Одновременное использование transactional и non-transactional таблиц отключено",
|
||||||
"Опция '%s' использована дважды",
|
"Опция '%s' использована дважды",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -235,3 +235,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -228,3 +228,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
@ -227,3 +227,4 @@
|
|||||||
"Kan inte utföra kommandot emedan du har ett READ lås",
|
"Kan inte utföra kommandot emedan du har ett READ lås",
|
||||||
"Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat",
|
"Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat",
|
||||||
"Option '%s' användes två gånger",
|
"Option '%s' användes två gånger",
|
||||||
|
"Användare '%-64s' har överskridit '%s' (nuvarande värde: %ld)",
|
||||||
|
@ -232,3 +232,4 @@
|
|||||||
"Can't execute the query because you have a conflicting read lock",
|
"Can't execute the query because you have a conflicting read lock",
|
||||||
"Mixing of transactional and non-transactional tables is disabled",
|
"Mixing of transactional and non-transactional tables is disabled",
|
||||||
"Option '%s' used twice in statement",
|
"Option '%s' used twice in statement",
|
||||||
|
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||||
|
477
sql/slave.cc
477
sql/slave.cc
@ -268,7 +268,7 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, bool just_reset, const char** errmsg)
|
|||||||
pthread_mutex_lock(&rli->data_lock);
|
pthread_mutex_lock(&rli->data_lock);
|
||||||
rli->pending=0;
|
rli->pending=0;
|
||||||
rli->master_log_name[0]=0;
|
rli->master_log_name[0]=0;
|
||||||
rli->master_log_pos=0; // 0 means uninitialized
|
rli->master_log_pos=0; // 0 means uninitialized
|
||||||
if (rli->relay_log.reset_logs(rli->sql_thd) ||
|
if (rli->relay_log.reset_logs(rli->sql_thd) ||
|
||||||
rli->relay_log.find_first_log(&rli->linfo,""))
|
rli->relay_log.find_first_log(&rli->linfo,""))
|
||||||
{
|
{
|
||||||
@ -990,7 +990,7 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
|
|||||||
}
|
}
|
||||||
if (init_relay_log_pos(rli,"",4,0/*no data mutex*/,&msg))
|
if (init_relay_log_pos(rli,"",4,0/*no data mutex*/,&msg))
|
||||||
goto err;
|
goto err;
|
||||||
rli->master_log_pos = 0; // uninitialized
|
rli->master_log_pos = 0; // uninitialized
|
||||||
rli->info_fd = info_fd;
|
rli->info_fd = info_fd;
|
||||||
}
|
}
|
||||||
else // file exists
|
else // file exists
|
||||||
@ -1049,6 +1049,7 @@ err:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
|
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
|
||||||
const char* slave_info_fname)
|
const char* slave_info_fname)
|
||||||
{
|
{
|
||||||
@ -1058,14 +1059,16 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
|
|||||||
return 1;
|
return 1;
|
||||||
mi->rli.mi = mi;
|
mi->rli.mi = mi;
|
||||||
mi->ignore_stop_event=0;
|
mi->ignore_stop_event=0;
|
||||||
int fd,length,error;
|
int fd,error;
|
||||||
MY_STAT stat_area;
|
MY_STAT stat_area;
|
||||||
char fname[FN_REFLEN+128];
|
char fname[FN_REFLEN+128];
|
||||||
const char *msg;
|
const char *msg;
|
||||||
fn_format(fname, master_info_fname, mysql_data_home, "", 4+32);
|
fn_format(fname, master_info_fname, mysql_data_home, "", 4+32);
|
||||||
|
|
||||||
// we need a mutex while we are changing master info parameters to
|
/*
|
||||||
// keep other threads from reading bogus info
|
We need a mutex while we are changing master info parameters to
|
||||||
|
keep other threads from reading bogus info
|
||||||
|
*/
|
||||||
|
|
||||||
pthread_mutex_lock(&mi->data_lock);
|
pthread_mutex_lock(&mi->data_lock);
|
||||||
fd = mi->fd;
|
fd = mi->fd;
|
||||||
@ -1089,7 +1092,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
mi->master_log_name[0] = 0;
|
mi->master_log_name[0] = 0;
|
||||||
mi->master_log_pos = 4; // skip magic number
|
mi->master_log_pos = 4; // skip magic number
|
||||||
mi->fd = fd;
|
mi->fd = fd;
|
||||||
|
|
||||||
if (master_host)
|
if (master_host)
|
||||||
@ -1119,20 +1122,18 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
|
|||||||
|
|
||||||
mi->fd = fd;
|
mi->fd = fd;
|
||||||
if (init_strvar_from_file(mi->master_log_name,
|
if (init_strvar_from_file(mi->master_log_name,
|
||||||
sizeof(mi->master_log_name), &mi->file,
|
sizeof(mi->master_log_name), &mi->file,
|
||||||
(char*)"") ||
|
(char*)"") ||
|
||||||
init_intvar_from_file((int*)&mi->master_log_pos, &mi->file, 4)
|
init_intvar_from_file((int*)&mi->master_log_pos, &mi->file, 4) ||
|
||||||
||
|
init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
|
||||||
init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
|
master_host) ||
|
||||||
master_host) ||
|
init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
|
||||||
init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
|
master_user) ||
|
||||||
master_user) ||
|
init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file,
|
||||||
init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file,
|
master_password) ||
|
||||||
master_password) ||
|
init_intvar_from_file((int*)&mi->port, &mi->file, master_port) ||
|
||||||
init_intvar_from_file((int*)&mi->port, &mi->file, master_port) ||
|
init_intvar_from_file((int*)&mi->connect_retry, &mi->file,
|
||||||
init_intvar_from_file((int*)&mi->connect_retry, &mi->file,
|
master_connect_retry))
|
||||||
master_connect_retry)
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
msg="Error reading master configuration";
|
msg="Error reading master configuration";
|
||||||
goto err;
|
goto err;
|
||||||
@ -1140,8 +1141,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
mi->inited = 1;
|
mi->inited = 1;
|
||||||
// now change the cache from READ to WRITE - must do this
|
// now change cache READ -> WRITE - must do this before flush_master_info
|
||||||
// before flush_master_info
|
|
||||||
reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1);
|
reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1);
|
||||||
error=test(flush_master_info(mi));
|
error=test(flush_master_info(mi));
|
||||||
pthread_mutex_unlock(&mi->data_lock);
|
pthread_mutex_unlock(&mi->data_lock);
|
||||||
@ -1250,7 +1250,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
|
|||||||
net_store_data(packet, (uint32)mi->rli.last_slave_errno);
|
net_store_data(packet, (uint32)mi->rli.last_slave_errno);
|
||||||
net_store_data(packet, mi->rli.last_slave_error);
|
net_store_data(packet, mi->rli.last_slave_error);
|
||||||
net_store_data(packet, mi->rli.slave_skip_counter);
|
net_store_data(packet, mi->rli.slave_skip_counter);
|
||||||
net_store_data(packet, (longlong)mi->rli.master_log_pos);
|
net_store_data(packet, (longlong) mi->rli.master_log_pos);
|
||||||
pthread_mutex_unlock(&mi->rli.data_lock);
|
pthread_mutex_unlock(&mi->rli.data_lock);
|
||||||
pthread_mutex_unlock(&mi->data_lock);
|
pthread_mutex_unlock(&mi->data_lock);
|
||||||
|
|
||||||
@ -1408,7 +1408,8 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi)
|
|||||||
int len;
|
int len;
|
||||||
int binlog_flags = 0; // for now
|
int binlog_flags = 0; // for now
|
||||||
char* logname = mi->master_log_name;
|
char* logname = mi->master_log_name;
|
||||||
int4store(buf, mi->master_log_pos);
|
// TODO if big log files: Change next to int8store()
|
||||||
|
int4store(buf, (longlong) mi->master_log_pos);
|
||||||
int2store(buf + 4, binlog_flags);
|
int2store(buf + 4, binlog_flags);
|
||||||
int4store(buf + 6, server_id);
|
int4store(buf + 6, server_id);
|
||||||
len = (uint) strlen(logname);
|
len = (uint) strlen(logname);
|
||||||
@ -1521,7 +1522,6 @@ point. If you are sure that your master is ok, run this query manually on the\
|
|||||||
|
|
||||||
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
|
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
|
||||||
{
|
{
|
||||||
const char *error_msg;
|
|
||||||
DBUG_ASSERT(rli->sql_thd==thd);
|
DBUG_ASSERT(rli->sql_thd==thd);
|
||||||
Log_event * ev = next_event(rli);
|
Log_event * ev = next_event(rli);
|
||||||
DBUG_ASSERT(rli->sql_thd==thd);
|
DBUG_ASSERT(rli->sql_thd==thd);
|
||||||
@ -1582,7 +1582,7 @@ This may also be a network problem, or just a bug in the master or slave code.\
|
|||||||
pthread_handler_decl(handle_slave_io,arg)
|
pthread_handler_decl(handle_slave_io,arg)
|
||||||
{
|
{
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
slave_begin:
|
slave_begin:
|
||||||
#endif
|
#endif
|
||||||
THD *thd; // needs to be first for thread_stack
|
THD *thd; // needs to be first for thread_stack
|
||||||
MYSQL *mysql = NULL ;
|
MYSQL *mysql = NULL ;
|
||||||
@ -1604,12 +1604,12 @@ pthread_handler_decl(handle_slave_io,arg)
|
|||||||
|
|
||||||
pthread_detach_this_thread();
|
pthread_detach_this_thread();
|
||||||
if (init_slave_thread(thd, SLAVE_THD_IO))
|
if (init_slave_thread(thd, SLAVE_THD_IO))
|
||||||
{
|
{
|
||||||
pthread_cond_broadcast(&mi->start_cond);
|
pthread_cond_broadcast(&mi->start_cond);
|
||||||
pthread_mutex_unlock(&mi->run_lock);
|
pthread_mutex_unlock(&mi->run_lock);
|
||||||
sql_print_error("Failed during slave I/O thread initialization");
|
sql_print_error("Failed during slave I/O thread initialization");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
mi->io_thd = thd;
|
mi->io_thd = thd;
|
||||||
thd->thread_stack = (char*)&thd; // remember where our stack is
|
thd->thread_stack = (char*)&thd; // remember where our stack is
|
||||||
threads.append(thd);
|
threads.append(thd);
|
||||||
@ -1633,11 +1633,11 @@ pthread_handler_decl(handle_slave_io,arg)
|
|||||||
#endif
|
#endif
|
||||||
// we can get killed during safe_connect
|
// we can get killed during safe_connect
|
||||||
if (!safe_connect(thd, mysql, mi))
|
if (!safe_connect(thd, mysql, mi))
|
||||||
sql_print_error("Slave I/O thread: connected to master '%s@%s:%d',\
|
sql_print_error("Slave I/O thread: connected to master '%s@%s:%d',\
|
||||||
replication started in log '%s' at position %s", mi->user,
|
replication started in log '%s' at position %s", mi->user,
|
||||||
mi->host, mi->port,
|
mi->host, mi->port,
|
||||||
IO_RPL_LOG_NAME,
|
IO_RPL_LOG_NAME,
|
||||||
llstr(mi->master_log_pos,llbuff));
|
llstr(mi->master_log_pos,llbuff));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sql_print_error("Slave I/O thread killed while connecting to master");
|
sql_print_error("Slave I/O thread killed while connecting to master");
|
||||||
@ -1649,14 +1649,14 @@ connected:
|
|||||||
thd->slave_net = &mysql->net;
|
thd->slave_net = &mysql->net;
|
||||||
thd->proc_info = "Checking master version";
|
thd->proc_info = "Checking master version";
|
||||||
if (check_master_version(mysql, mi))
|
if (check_master_version(mysql, mi))
|
||||||
{
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
|
||||||
if (!mi->old_format)
|
if (!mi->old_format)
|
||||||
{
|
{
|
||||||
// register ourselves with the master
|
/*
|
||||||
// if fails, this is not fatal - we just print the error message and go
|
Register ourselves with the master.
|
||||||
// on with life
|
If fails, this is not fatal - we just print the error message and go
|
||||||
|
on with life.
|
||||||
|
*/
|
||||||
thd->proc_info = "Registering slave on master";
|
thd->proc_info = "Registering slave on master";
|
||||||
if (register_slave_on_master(mysql) || update_slave_list(mysql))
|
if (register_slave_on_master(mysql) || update_slave_list(mysql))
|
||||||
goto err;
|
goto err;
|
||||||
@ -1664,122 +1664,124 @@ connected:
|
|||||||
|
|
||||||
while (!slave_killed(thd,mi))
|
while (!slave_killed(thd,mi))
|
||||||
{
|
{
|
||||||
thd->proc_info = "Requesting binlog dump";
|
thd->proc_info = "Requesting binlog dump";
|
||||||
if (request_dump(mysql, mi))
|
if (request_dump(mysql, mi))
|
||||||
{
|
{
|
||||||
sql_print_error("Failed on request_dump()");
|
sql_print_error("Failed on request_dump()");
|
||||||
if(slave_killed(thd,mi))
|
if(slave_killed(thd,mi))
|
||||||
{
|
{
|
||||||
sql_print_error("Slave I/O thread killed while requesting master \
|
sql_print_error("Slave I/O thread killed while requesting master \
|
||||||
dump");
|
dump");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
thd->proc_info = "Waiiting to reconnect after a failed dump request";
|
thd->proc_info = "Waiiting to reconnect after a failed dump request";
|
||||||
mc_end_server(mysql);
|
mc_end_server(mysql);
|
||||||
// first time retry immediately, assuming that we can recover
|
/*
|
||||||
// right away - if first time fails, sleep between re-tries
|
First time retry immediately, assuming that we can recover
|
||||||
// hopefuly the admin can fix the problem sometime
|
right away - if first time fails, sleep between re-tries
|
||||||
if (retried_once)
|
hopefuly the admin can fix the problem sometime
|
||||||
safe_sleep(thd, mi, mi->connect_retry);
|
*/
|
||||||
else
|
if (retried_once)
|
||||||
retried_once = 1;
|
safe_sleep(thd, mi, mi->connect_retry);
|
||||||
|
else
|
||||||
|
retried_once = 1;
|
||||||
|
|
||||||
if (slave_killed(thd,mi))
|
if (slave_killed(thd,mi))
|
||||||
{
|
{
|
||||||
sql_print_error("Slave I/O thread killed while retrying master \
|
sql_print_error("Slave I/O thread killed while retrying master \
|
||||||
dump");
|
dump");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
thd->proc_info = "Reconnecting after a failed dump request";
|
thd->proc_info = "Reconnecting after a failed dump request";
|
||||||
sql_print_error("Slave I/O thread: failed dump request, \
|
sql_print_error("Slave I/O thread: failed dump request, \
|
||||||
reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
|
reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
|
||||||
llstr(mi->master_log_pos,llbuff));
|
llstr(mi->master_log_pos,llbuff));
|
||||||
if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi))
|
if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi))
|
||||||
{
|
{
|
||||||
sql_print_error("Slave I/O thread killed during or \
|
sql_print_error("Slave I/O thread killed during or \
|
||||||
after reconnect");
|
after reconnect");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
goto connected;
|
goto connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!slave_killed(thd,mi))
|
while (!slave_killed(thd,mi))
|
||||||
{
|
{
|
||||||
thd->proc_info = "Reading master update";
|
thd->proc_info = "Reading master update";
|
||||||
ulong event_len = read_event(mysql, mi);
|
ulong event_len = read_event(mysql, mi);
|
||||||
if (slave_killed(thd,mi))
|
if (slave_killed(thd,mi))
|
||||||
{
|
{
|
||||||
sql_print_error("Slave I/O thread killed while reading event");
|
sql_print_error("Slave I/O thread killed while reading event");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event_len == packet_error)
|
if (event_len == packet_error)
|
||||||
{
|
{
|
||||||
if (mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE)
|
if (mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE)
|
||||||
{
|
{
|
||||||
sql_print_error("Log entry on master is longer than \
|
sql_print_error("Log entry on master is longer than \
|
||||||
max_allowed_packet on slave. Slave thread will be aborted. If the entry is \
|
max_allowed_packet (%ld) on slave. Slave thread will be aborted. If the entry \
|
||||||
really supposed to be that long, restart the server with a higher value of \
|
is correct, restart the server with a higher value of max_allowed_packet",
|
||||||
max_allowed_packet. The current value is %ld", max_allowed_packet);
|
max_allowed_packet);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
thd->proc_info = "Waiting to reconnect after a failed read";
|
thd->proc_info = "Waiting to reconnect after a failed read";
|
||||||
mc_end_server(mysql);
|
mc_end_server(mysql);
|
||||||
if (retried_once) // punish repeat offender with sleep
|
if (retried_once) // punish repeat offender with sleep
|
||||||
safe_sleep(thd,mi,mi->connect_retry);
|
safe_sleep(thd,mi,mi->connect_retry);
|
||||||
else
|
else
|
||||||
retried_once = 1;
|
retried_once = 1;
|
||||||
|
|
||||||
if (slave_killed(thd,mi))
|
if (slave_killed(thd,mi))
|
||||||
{
|
{
|
||||||
sql_print_error("Slave I/O thread killed while waiting to \
|
sql_print_error("Slave I/O thread killed while waiting to \
|
||||||
reconnect after a failed read");
|
reconnect after a failed read");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
thd->proc_info = "Reconnecting after a failed read";
|
thd->proc_info = "Reconnecting after a failed read";
|
||||||
sql_print_error("Slave I/O thread: Failed reading log event, \
|
sql_print_error("Slave I/O thread: Failed reading log event, \
|
||||||
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
|
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
|
||||||
llstr(mi->master_log_pos, llbuff));
|
llstr(mi->master_log_pos, llbuff));
|
||||||
if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi))
|
if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi))
|
||||||
{
|
{
|
||||||
sql_print_error("Slave I/O thread killed during or after a \
|
sql_print_error("Slave I/O thread killed during or after a \
|
||||||
reconnect done to recover from failed read");
|
reconnect done to recover from failed read");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
goto connected;
|
goto connected;
|
||||||
} // if(event_len == packet_error)
|
} // if(event_len == packet_error)
|
||||||
|
|
||||||
thd->proc_info = "Queueing event from master";
|
thd->proc_info = "Queueing event from master";
|
||||||
if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
|
if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
|
||||||
(uint)event_len))
|
event_len))
|
||||||
{
|
{
|
||||||
sql_print_error("Slave I/O thread could not queue event \
|
sql_print_error("Slave I/O thread could not queue event \
|
||||||
from master");
|
from master");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
// TODO: check debugging abort code
|
// TODO: check debugging abort code
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
if (abort_slave_event_count && !--events_till_abort)
|
if (abort_slave_event_count && !--events_till_abort)
|
||||||
{
|
{
|
||||||
sql_print_error("Slave I/O thread: debugging abort");
|
sql_print_error("Slave I/O thread: debugging abort");
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} // while(!slave_killed(thd,mi)) - read/exec loop
|
} // while(!slave_killed(thd,mi)) - read/exec loop
|
||||||
} // while(!slave_killed(thd,mi)) - slave loop
|
} // while(!slave_killed(thd,mi)) - slave loop
|
||||||
|
|
||||||
// error = 0;
|
// error = 0;
|
||||||
err:
|
err:
|
||||||
// print the current replication position
|
// print the current replication position
|
||||||
sql_print_error("Slave I/O thread exiting, read up to log '%s', position %s",
|
sql_print_error("Slave I/O thread exiting, read up to log '%s', position %s",
|
||||||
IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
|
IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
|
||||||
thd->query = thd->db = 0; // extra safety
|
thd->query = thd->db = 0; // extra safety
|
||||||
if(mysql)
|
if(mysql)
|
||||||
mc_mysql_close(mysql);
|
mc_mysql_close(mysql);
|
||||||
thd->proc_info = "Waiting for slave mutex on exit";
|
thd->proc_info = "Waiting for slave mutex on exit";
|
||||||
pthread_mutex_lock(&mi->run_lock);
|
pthread_mutex_lock(&mi->run_lock);
|
||||||
mi->slave_running = 0;
|
mi->slave_running = 0;
|
||||||
@ -1803,12 +1805,13 @@ from master");
|
|||||||
DBUG_RETURN(0); // Can't return anything here
|
DBUG_RETURN(0); // Can't return anything here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* slave SQL logic thread */
|
/* slave SQL logic thread */
|
||||||
|
|
||||||
pthread_handler_decl(handle_slave_sql,arg)
|
pthread_handler_decl(handle_slave_sql,arg)
|
||||||
{
|
{
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
slave_begin:
|
slave_begin:
|
||||||
#endif
|
#endif
|
||||||
THD *thd; /* needs to be first for thread_stack */
|
THD *thd; /* needs to be first for thread_stack */
|
||||||
MYSQL *mysql = NULL ;
|
MYSQL *mysql = NULL ;
|
||||||
@ -1832,14 +1835,16 @@ pthread_handler_decl(handle_slave_sql,arg)
|
|||||||
|
|
||||||
pthread_detach_this_thread();
|
pthread_detach_this_thread();
|
||||||
if (init_slave_thread(thd, SLAVE_THD_SQL))
|
if (init_slave_thread(thd, SLAVE_THD_SQL))
|
||||||
{
|
{
|
||||||
// TODO: this is currently broken - slave start and change master
|
/*
|
||||||
// will be stuck if we fail here
|
TODO: this is currently broken - slave start and change master
|
||||||
pthread_cond_broadcast(&rli->start_cond);
|
will be stuck if we fail here
|
||||||
pthread_mutex_unlock(&rli->run_lock);
|
*/
|
||||||
sql_print_error("Failed during slave thread initialization");
|
pthread_cond_broadcast(&rli->start_cond);
|
||||||
goto err;
|
pthread_mutex_unlock(&rli->run_lock);
|
||||||
}
|
sql_print_error("Failed during slave thread initialization");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
thd->thread_stack = (char*)&thd; // remember where our stack is
|
thd->thread_stack = (char*)&thd; // remember where our stack is
|
||||||
thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
|
thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
|
||||||
threads.append(thd);
|
threads.append(thd);
|
||||||
@ -1876,7 +1881,7 @@ log '%s' at position %s,relay log: name='%s',pos='%s'", RPL_LOG_NAME,
|
|||||||
if (!slave_killed(thd,rli))
|
if (!slave_killed(thd,rli))
|
||||||
sql_print_error("\
|
sql_print_error("\
|
||||||
Error running query, slave SQL thread aborted. Fix the problem, and restart \
|
Error running query, slave SQL thread aborted. Fix the problem, and restart \
|
||||||
the slave SQL thread with \"mysqladmin start-slave\". We stopped at log \
|
the slave SQL thread with \"SLAVE START\". We stopped at log \
|
||||||
'%s' position %s",
|
'%s' position %s",
|
||||||
RPL_LOG_NAME, llstr(rli->master_log_pos, llbuff));
|
RPL_LOG_NAME, llstr(rli->master_log_pos, llbuff));
|
||||||
goto err;
|
goto err;
|
||||||
@ -1895,8 +1900,11 @@ the slave SQL thread with \"mysqladmin start-slave\". We stopped at log \
|
|||||||
DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
|
DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
|
||||||
rli->slave_running = 0;
|
rli->slave_running = 0;
|
||||||
rli->save_temporary_tables = thd->temporary_tables;
|
rli->save_temporary_tables = thd->temporary_tables;
|
||||||
//TODO: see if we can do this conditionally in next_event() instead
|
|
||||||
// to avoid unneeded position re-init
|
/*
|
||||||
|
TODO: see if we can do this conditionally in next_event() instead
|
||||||
|
to avoid unneeded position re-init
|
||||||
|
*/
|
||||||
rli->log_pos_current=0;
|
rli->log_pos_current=0;
|
||||||
thd->temporary_tables = 0; // remove tempation from destructor to close them
|
thd->temporary_tables = 0; // remove tempation from destructor to close them
|
||||||
DBUG_ASSERT(thd->net.buff != 0);
|
DBUG_ASSERT(thd->net.buff != 0);
|
||||||
@ -1918,6 +1926,7 @@ the slave SQL thread with \"mysqladmin start-slave\". We stopped at log \
|
|||||||
DBUG_RETURN(0); // Can't return anything here
|
DBUG_RETURN(0); // Can't return anything here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// We assume we already locked mi->data_lock
|
// We assume we already locked mi->data_lock
|
||||||
static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev)
|
static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev)
|
||||||
{
|
{
|
||||||
@ -1929,39 +1938,41 @@ static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev)
|
|||||||
mi->master_log_name[rev->ident_len] = 0;
|
mi->master_log_name[rev->ident_len] = 0;
|
||||||
mi->master_log_pos = rev->pos;
|
mi->master_log_pos = rev->pos;
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
/* if we do not do this, we will be getting the first
|
/*
|
||||||
rotate event forever, so
|
If we do not do this, we will be getting the first
|
||||||
we need to not disconnect after one
|
rotate event forever, so we need to not disconnect after one.
|
||||||
*/
|
*/
|
||||||
if (disconnect_slave_event_count)
|
if (disconnect_slave_event_count)
|
||||||
events_till_disconnect++;
|
events_till_disconnect++;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: verify the issue with stop events, see if we need them at all
|
/*
|
||||||
// in the relay log
|
TODO: verify the issue with stop events, see if we need them at all
|
||||||
// TODO: test this code before release - it has to be tested on a separte
|
in the relay log
|
||||||
// setup with 3.23 master
|
TODO: test this code before release - it has to be tested on a separte
|
||||||
static int queue_old_event(MASTER_INFO* mi, const char* buf,
|
setup with 3.23 master
|
||||||
uint event_len)
|
*/
|
||||||
|
|
||||||
|
static int queue_old_event(MASTER_INFO *mi, const char *buf,
|
||||||
|
ulong event_len)
|
||||||
{
|
{
|
||||||
const char* errmsg = 0;
|
const char *errmsg = 0;
|
||||||
bool inc_pos = 1;
|
bool inc_pos = 1;
|
||||||
bool processed_stop_event = 0;
|
bool processed_stop_event = 0;
|
||||||
Log_event* ev = Log_event::read_log_event(buf,event_len, &errmsg,
|
Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
|
||||||
1/*old format*/);
|
1 /*old format*/ );
|
||||||
if (unlikely(!ev))
|
if (unlikely(!ev))
|
||||||
{
|
{
|
||||||
sql_print_error("Read invalid event from master: '%s',\
|
sql_print_error("Read invalid event from master: '%s',\
|
||||||
master could be corrupt but a more likely cause of this is a bug",
|
master could be corrupt but a more likely cause of this is a bug",
|
||||||
errmsg);
|
errmsg);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
pthread_mutex_lock(&mi->data_lock);
|
pthread_mutex_lock(&mi->data_lock);
|
||||||
ev->log_pos = mi->master_log_pos;
|
ev->log_pos = mi->master_log_pos;
|
||||||
switch (ev->get_type_code())
|
switch (ev->get_type_code()) {
|
||||||
{
|
|
||||||
case ROTATE_EVENT:
|
case ROTATE_EVENT:
|
||||||
if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
|
if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev)))
|
||||||
{
|
{
|
||||||
@ -2003,9 +2014,12 @@ static int queue_old_event(MASTER_INFO* mi, const char* buf,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: verify the issue with stop events, see if we need them at all
|
/*
|
||||||
// in the relay log
|
TODO: verify the issue with stop events, see if we need them at all
|
||||||
int queue_event(MASTER_INFO* mi,const char* buf,uint event_len)
|
in the relay log
|
||||||
|
*/
|
||||||
|
|
||||||
|
int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
|
||||||
{
|
{
|
||||||
int error=0;
|
int error=0;
|
||||||
bool inc_pos = 1;
|
bool inc_pos = 1;
|
||||||
@ -2015,10 +2029,11 @@ int queue_event(MASTER_INFO* mi,const char* buf,uint event_len)
|
|||||||
|
|
||||||
pthread_mutex_lock(&mi->data_lock);
|
pthread_mutex_lock(&mi->data_lock);
|
||||||
|
|
||||||
// TODO: figure out if other events in addition to Rotate
|
/*
|
||||||
// require special processing
|
TODO: figure out if other events in addition to Rotate
|
||||||
switch (buf[EVENT_TYPE_OFFSET])
|
require special processing
|
||||||
{
|
*/
|
||||||
|
switch (buf[EVENT_TYPE_OFFSET]) {
|
||||||
case STOP_EVENT:
|
case STOP_EVENT:
|
||||||
processed_stop_event=1;
|
processed_stop_event=1;
|
||||||
break;
|
break;
|
||||||
@ -2048,22 +2063,23 @@ int queue_event(MASTER_INFO* mi,const char* buf,uint event_len)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void end_relay_log_info(RELAY_LOG_INFO* rli)
|
void end_relay_log_info(RELAY_LOG_INFO* rli)
|
||||||
{
|
{
|
||||||
if (!rli->inited)
|
if (!rli->inited)
|
||||||
return;
|
return;
|
||||||
if (rli->info_fd >= 0)
|
if (rli->info_fd >= 0)
|
||||||
{
|
{
|
||||||
end_io_cache(&rli->info_file);
|
end_io_cache(&rli->info_file);
|
||||||
(void)my_close(rli->info_fd, MYF(MY_WME));
|
(void)my_close(rli->info_fd, MYF(MY_WME));
|
||||||
rli->info_fd = -1;
|
rli->info_fd = -1;
|
||||||
}
|
}
|
||||||
if (rli->cur_log_fd >= 0)
|
if (rli->cur_log_fd >= 0)
|
||||||
{
|
{
|
||||||
end_io_cache(&rli->cache_buf);
|
end_io_cache(&rli->cache_buf);
|
||||||
(void)my_close(rli->cur_log_fd, MYF(MY_WME));
|
(void)my_close(rli->cur_log_fd, MYF(MY_WME));
|
||||||
rli->cur_log_fd = -1;
|
rli->cur_log_fd = -1;
|
||||||
}
|
}
|
||||||
rli->inited = 0;
|
rli->inited = 0;
|
||||||
rli->log_pos_current=0;
|
rli->log_pos_current=0;
|
||||||
rli->relay_log.close(1);
|
rli->relay_log.close(1);
|
||||||
@ -2075,10 +2091,12 @@ static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
|
|||||||
return connect_to_master(thd, mysql, mi, 0);
|
return connect_to_master(thd, mysql, mi, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Try to connect until successful or slave killed or we have retried
|
Try to connect until successful or slave killed or we have retried
|
||||||
master_retry_count times
|
master_retry_count times
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
|
static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
|
||||||
bool reconnect)
|
bool reconnect)
|
||||||
{
|
{
|
||||||
@ -2091,9 +2109,9 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
|
|||||||
events_till_disconnect = disconnect_slave_event_count;
|
events_till_disconnect = disconnect_slave_event_count;
|
||||||
#endif
|
#endif
|
||||||
while (!(slave_was_killed = slave_killed(thd,mi)) &&
|
while (!(slave_was_killed = slave_killed(thd,mi)) &&
|
||||||
(reconnect ? mc_mysql_reconnect(mysql) :
|
(reconnect ? mc_mysql_reconnect(mysql) != 0 :
|
||||||
!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0,
|
!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0,
|
||||||
mi->port, 0, 0)))
|
mi->port, 0, 0)))
|
||||||
{
|
{
|
||||||
/* Don't repeat last error */
|
/* Don't repeat last error */
|
||||||
if (mc_mysql_errno(mysql) != last_errno)
|
if (mc_mysql_errno(mysql) != last_errno)
|
||||||
@ -2105,10 +2123,11 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
|
|||||||
mi->connect_retry);
|
mi->connect_retry);
|
||||||
}
|
}
|
||||||
safe_sleep(thd,mi,mi->connect_retry);
|
safe_sleep(thd,mi,mi->connect_retry);
|
||||||
/* by default we try forever. The reason is that failure will trigger
|
/*
|
||||||
master election, so if the user did not set master_retry_count we
|
By default we try forever. The reason is that failure will trigger
|
||||||
do not want to have electioin triggered on the first failure to
|
master election, so if the user did not set master_retry_count we
|
||||||
connect
|
do not want to have electioin triggered on the first failure to
|
||||||
|
connect
|
||||||
*/
|
*/
|
||||||
if (master_retry_count && err_count++ == master_retry_count)
|
if (master_retry_count && err_count++ == master_retry_count)
|
||||||
{
|
{
|
||||||
@ -2124,14 +2143,14 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
|
|||||||
if (reconnect)
|
if (reconnect)
|
||||||
sql_print_error("Slave: connected to master '%s@%s:%d',\
|
sql_print_error("Slave: connected to master '%s@%s:%d',\
|
||||||
replication resumed in log '%s' at position %s", mi->user,
|
replication resumed in log '%s' at position %s", mi->user,
|
||||||
mi->host, mi->port,
|
mi->host, mi->port,
|
||||||
IO_RPL_LOG_NAME,
|
IO_RPL_LOG_NAME,
|
||||||
llstr(mi->master_log_pos,llbuff));
|
llstr(mi->master_log_pos,llbuff));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
change_rpl_status(RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE);
|
change_rpl_status(RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE);
|
||||||
mysql_log.write(thd, COM_CONNECT_OUT, "%s@%s:%d",
|
mysql_log.write(thd, COM_CONNECT_OUT, "%s@%s:%d",
|
||||||
mi->user, mi->host, mi->port);
|
mi->user, mi->host, mi->port);
|
||||||
}
|
}
|
||||||
#ifdef SIGNAL_WITH_VIO_CLOSE
|
#ifdef SIGNAL_WITH_VIO_CLOSE
|
||||||
thd->set_active_vio(mysql->net.vio);
|
thd->set_active_vio(mysql->net.vio);
|
||||||
@ -2141,6 +2160,7 @@ replication resumed in log '%s' at position %s", mi->user,
|
|||||||
return slave_was_killed;
|
return slave_was_killed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Try to connect until successful or slave killed or we have retried
|
Try to connect until successful or slave killed or we have retried
|
||||||
master_retry_count times
|
master_retry_count times
|
||||||
@ -2172,7 +2192,7 @@ IO_CACHE* reopen_relay_log(RELAY_LOG_INFO* rli, const char** errmsg)
|
|||||||
IO_CACHE* cur_log = rli->cur_log=&rli->cache_buf;
|
IO_CACHE* cur_log = rli->cur_log=&rli->cache_buf;
|
||||||
DBUG_ASSERT(rli->cur_log_fd == -1);
|
DBUG_ASSERT(rli->cur_log_fd == -1);
|
||||||
if ((rli->cur_log_fd=open_binlog(cur_log,rli->relay_log_name,
|
if ((rli->cur_log_fd=open_binlog(cur_log,rli->relay_log_name,
|
||||||
errmsg))<0)
|
errmsg)) <0)
|
||||||
return 0;
|
return 0;
|
||||||
my_b_seek(cur_log,rli->relay_log_pos);
|
my_b_seek(cur_log,rli->relay_log_pos);
|
||||||
return cur_log;
|
return cur_log;
|
||||||
@ -2188,29 +2208,36 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
|
|||||||
bool was_killed;
|
bool was_killed;
|
||||||
DBUG_ASSERT(thd != 0);
|
DBUG_ASSERT(thd != 0);
|
||||||
|
|
||||||
// For most operations we need to protect rli members with data_lock,
|
/*
|
||||||
// so we will hold it for the most of the loop below
|
For most operations we need to protect rli members with data_lock,
|
||||||
// However, we will release it whenever it is worth the hassle,
|
so we will hold it for the most of the loop below
|
||||||
// and in the cases when we go into a pthread_cond_wait() with the
|
However, we will release it whenever it is worth the hassle,
|
||||||
// non-data_lock mutex
|
and in the cases when we go into a pthread_cond_wait() with the
|
||||||
|
non-data_lock mutex
|
||||||
|
*/
|
||||||
pthread_mutex_lock(&rli->data_lock);
|
pthread_mutex_lock(&rli->data_lock);
|
||||||
|
|
||||||
for (;!(was_killed=slave_killed(thd,rli));)
|
for (; !(was_killed=slave_killed(thd,rli)) ;)
|
||||||
{
|
{
|
||||||
// we can have two kinds of log reading:
|
/*
|
||||||
// hot_log - rli->cur_log points at the IO_CACHE of relay_log, which
|
We can have two kinds of log reading:
|
||||||
// is actively being updated by the I/O thread. We need to be careful
|
hot_log - rli->cur_log points at the IO_CACHE of relay_log, which
|
||||||
// in this case and make sure that we are not looking at a stale log that
|
is actively being updated by the I/O thread. We need to be careful
|
||||||
// has already been rotated. If it has been, we reopen the log
|
in this case and make sure that we are not looking at a stale log that
|
||||||
// the other case is much simpler - we just have a read only log that
|
has already been rotated. If it has been, we reopen the log
|
||||||
// nobody else will be updating.
|
the other case is much simpler - we just have a read only log that
|
||||||
|
nobody else will be updating.
|
||||||
|
*/
|
||||||
bool hot_log;
|
bool hot_log;
|
||||||
if ((hot_log = (cur_log != &rli->cache_buf)))
|
if ((hot_log = (cur_log != &rli->cache_buf)))
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(rli->cur_log_fd == -1); // foreign descriptor
|
DBUG_ASSERT(rli->cur_log_fd == -1); // foreign descriptor
|
||||||
pthread_mutex_lock(log_lock);
|
pthread_mutex_lock(log_lock);
|
||||||
// reading cur_log->init_count here is safe because the log will only
|
|
||||||
// be rotated when we hold relay_log.LOCK_log
|
/*
|
||||||
|
Reading cur_log->init_count here is safe because the log will only
|
||||||
|
be rotated when we hold relay_log.LOCK_log
|
||||||
|
*/
|
||||||
if (cur_log->init_count != rli->cur_log_init_count)
|
if (cur_log->init_count != rli->cur_log_init_count)
|
||||||
{
|
{
|
||||||
if (!(cur_log=reopen_relay_log(rli,&errmsg)))
|
if (!(cur_log=reopen_relay_log(rli,&errmsg)))
|
||||||
@ -2235,29 +2262,37 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
|
|||||||
DBUG_ASSERT(thd==rli->sql_thd);
|
DBUG_ASSERT(thd==rli->sql_thd);
|
||||||
if (!cur_log->error) /* EOF */
|
if (!cur_log->error) /* EOF */
|
||||||
{
|
{
|
||||||
// on a hot log, EOF means that there are no more updates to
|
/*
|
||||||
// process and we must block until I/O thread adds some and
|
On a hot log, EOF means that there are no more updates to
|
||||||
// signals us to continue
|
process and we must block until I/O thread adds some and
|
||||||
|
signals us to continue
|
||||||
|
*/
|
||||||
if (hot_log)
|
if (hot_log)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(cur_log->init_count == rli->cur_log_init_count);
|
DBUG_ASSERT(cur_log->init_count == rli->cur_log_init_count);
|
||||||
//we can, and should release data_lock while we are waiting for
|
/*
|
||||||
// update. If we do not, show slave status will block
|
We can, and should release data_lock while we are waiting for
|
||||||
|
update. If we do not, show slave status will block
|
||||||
|
*/
|
||||||
pthread_mutex_unlock(&rli->data_lock);
|
pthread_mutex_unlock(&rli->data_lock);
|
||||||
|
|
||||||
// IMPORTANT: note that wait_for_update will unlock LOCK_log, but
|
/*
|
||||||
// expects the caller to lock it
|
IMPORTANT: note that wait_for_update will unlock LOCK_log, but
|
||||||
|
expects the caller to lock it
|
||||||
|
*/
|
||||||
rli->relay_log.wait_for_update(rli->sql_thd);
|
rli->relay_log.wait_for_update(rli->sql_thd);
|
||||||
|
|
||||||
// re-acquire data lock since we released it earlier
|
// re-acquire data lock since we released it earlier
|
||||||
pthread_mutex_lock(&rli->data_lock);
|
pthread_mutex_lock(&rli->data_lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// if the log was not hot, we need to move to the next log in
|
|
||||||
// sequence. The next log could be hot or cold, we deal with both
|
|
||||||
// cases separately after doing some common initialization
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
If the log was not hot, we need to move to the next log in
|
||||||
|
sequence. The next log could be hot or cold, we deal with both
|
||||||
|
cases separately after doing some common initialization
|
||||||
|
*/
|
||||||
end_io_cache(cur_log);
|
end_io_cache(cur_log);
|
||||||
DBUG_ASSERT(rli->cur_log_fd >= 0);
|
DBUG_ASSERT(rli->cur_log_fd >= 0);
|
||||||
my_close(rli->cur_log_fd, MYF(MY_WME));
|
my_close(rli->cur_log_fd, MYF(MY_WME));
|
||||||
@ -2282,21 +2317,25 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
|
|||||||
rli->cur_log_init_count = cur_log->init_count;
|
rli->cur_log_init_count = cur_log->init_count;
|
||||||
DBUG_ASSERT(rli->cur_log_fd == -1);
|
DBUG_ASSERT(rli->cur_log_fd == -1);
|
||||||
|
|
||||||
// read pointer has to be at the start since we are the only
|
/*
|
||||||
// reader
|
Read pointer has to be at the start since we are the only
|
||||||
|
reader
|
||||||
|
*/
|
||||||
if (check_binlog_magic(cur_log,&errmsg))
|
if (check_binlog_magic(cur_log,&errmsg))
|
||||||
goto err;
|
goto err;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// if we get here, the log was not hot, so we will have to
|
/*
|
||||||
// open it ourselves
|
if we get here, the log was not hot, so we will have to
|
||||||
|
open it ourselves
|
||||||
|
*/
|
||||||
#ifdef EXTRA_DEBUG
|
#ifdef EXTRA_DEBUG
|
||||||
sql_print_error("next log '%s' is not active",
|
sql_print_error("next log '%s' is not active",
|
||||||
rli->linfo.log_file_name);
|
rli->linfo.log_file_name);
|
||||||
#endif
|
#endif
|
||||||
// open_binlog() will check the magic header
|
// open_binlog() will check the magic header
|
||||||
if ((rli->cur_log_fd=open_binlog(cur_log,rli->linfo.log_file_name,
|
if ((rli->cur_log_fd=open_binlog(cur_log,rli->linfo.log_file_name,
|
||||||
&errmsg))<0)
|
&errmsg)) <0)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
189
sql/slave.h
189
sql/slave.h
@ -33,8 +33,11 @@ extern my_string opt_relay_logname, opt_relaylog_index_name;
|
|||||||
extern bool opt_skip_slave_start;
|
extern bool opt_skip_slave_start;
|
||||||
struct st_master_info;
|
struct st_master_info;
|
||||||
|
|
||||||
// TODO: this needs to be redone, but for now it does not matter since
|
/*
|
||||||
// we do not have multi-master yet.
|
TODO: this needs to be redone, but for now it does not matter since
|
||||||
|
we do not have multi-master yet.
|
||||||
|
*/
|
||||||
|
|
||||||
#define LOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \
|
#define LOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \
|
||||||
++active_mi_in_use; \
|
++active_mi_in_use; \
|
||||||
pthread_mutex_unlock(&LOCK_active_mi);}
|
pthread_mutex_unlock(&LOCK_active_mi);}
|
||||||
@ -62,50 +65,64 @@ struct st_master_info;
|
|||||||
|
|
||||||
To clean up, call end_relay_log_info()
|
To clean up, call end_relay_log_info()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct st_relay_log_info
|
typedef struct st_relay_log_info
|
||||||
{
|
{
|
||||||
// info_fd - file descriptor of the info file. set only during
|
/*** The following variables can only be read when protect by data lock ****/
|
||||||
// initialization or clean up - safe to read anytime
|
/*
|
||||||
// cur_log_fd - file descriptor of the current read relay log, protected by
|
info_fd - file descriptor of the info file. set only during
|
||||||
// data_lock
|
initialization or clean up - safe to read anytime
|
||||||
|
cur_log_fd - file descriptor of the current read relay log
|
||||||
|
*/
|
||||||
File info_fd,cur_log_fd;
|
File info_fd,cur_log_fd;
|
||||||
|
// name of current read relay log
|
||||||
// IO_CACHE of the info file - set only during init or end, safe to read
|
char relay_log_name[FN_REFLEN];
|
||||||
// anytime
|
// master log name corresponding to current read position
|
||||||
|
char master_log_name[FN_REFLEN];
|
||||||
|
// original log position of last processed event
|
||||||
|
volatile my_off_t master_log_pos;
|
||||||
|
|
||||||
|
/*
|
||||||
|
current offset in the relay log.
|
||||||
|
pending - in some cases we do not increment offset immediately after
|
||||||
|
processing an event, because the following event needs to be processed
|
||||||
|
atomically together with this one ( so far, there is only one type of
|
||||||
|
such event - Intvar_event that sets auto_increment value). However, once
|
||||||
|
both events have been processed, we need to increment by the cumulative
|
||||||
|
offset. pending stored the extra offset to be added to the position.
|
||||||
|
*/
|
||||||
|
ulonglong relay_log_pos, pending;
|
||||||
|
|
||||||
|
// protected with internal locks
|
||||||
|
// must get data_lock when resetting the logs
|
||||||
|
MYSQL_LOG relay_log;
|
||||||
|
LOG_INFO linfo;
|
||||||
|
IO_CACHE cache_buf,*cur_log;
|
||||||
|
|
||||||
|
/*** The following variables are safe to read any time ***/
|
||||||
|
|
||||||
|
// IO_CACHE of the info file - set only during init or end
|
||||||
IO_CACHE info_file;
|
IO_CACHE info_file;
|
||||||
|
|
||||||
// name of current read relay log - protected by data_lock
|
/*
|
||||||
char relay_log_name[FN_REFLEN];
|
When we restart slave thread we need to have access to the previously
|
||||||
|
created temporary tables. Modified only on init/end and by the SQL
|
||||||
// master log name corresponding to current read position - protected by
|
thread, read only by SQL thread.
|
||||||
// data lock
|
*/
|
||||||
char master_log_name[FN_REFLEN];
|
|
||||||
|
|
||||||
// original log position of last processed event - protected by data_lock
|
|
||||||
volatile uint32 master_log_pos;
|
|
||||||
|
|
||||||
// when we restart slave thread we need to have access to the previously
|
|
||||||
// created temporary tables. Modified only on init/end and by the SQL
|
|
||||||
// thread, read only by SQL thread, need no mutex
|
|
||||||
TABLE* save_temporary_tables;
|
TABLE* save_temporary_tables;
|
||||||
|
|
||||||
// relay_log_pos - current offset in the relay log - protected by data_lock
|
/*
|
||||||
// pending - in some cases we do not increment offset immediately after
|
standard lock acquistion order to avoid deadlocks:
|
||||||
// processing an event, because the following event needs to be processed
|
run_lock, data_lock, relay_log.LOCK_log, relay_log.LOCK_index
|
||||||
// atomically together with this one ( so far, there is only one type of
|
*/
|
||||||
// such event - Intvar_event that sets auto_increment value). However, once
|
|
||||||
// both events have been processed, we need to increment by the cumulative
|
|
||||||
// offset. pending stored the extra offset to be added to the position.
|
|
||||||
ulonglong relay_log_pos,pending;
|
|
||||||
|
|
||||||
// standard lock acquistion order to avoid deadlocks:
|
|
||||||
// run_lock, data_lock, relay_log.LOCK_log,relay_log.LOCK_index
|
|
||||||
pthread_mutex_t data_lock,run_lock;
|
pthread_mutex_t data_lock,run_lock;
|
||||||
|
|
||||||
// start_cond is broadcast when SQL thread is started
|
/*
|
||||||
// stop_cond - when stopped
|
start_cond is broadcast when SQL thread is started
|
||||||
// data_cond - when data protected by data_lock changes
|
stop_cond - when stopped
|
||||||
pthread_cond_t start_cond,stop_cond,data_cond;
|
data_cond - when data protected by data_lock changes
|
||||||
|
*/
|
||||||
|
pthread_cond_t start_cond, stop_cond, data_cond;
|
||||||
|
|
||||||
// if not set, the value of other members of the structure are undefined
|
// if not set, the value of other members of the structure are undefined
|
||||||
bool inited;
|
bool inited;
|
||||||
@ -113,21 +130,19 @@ typedef struct st_relay_log_info
|
|||||||
// parent master info structure
|
// parent master info structure
|
||||||
struct st_master_info *mi;
|
struct st_master_info *mi;
|
||||||
|
|
||||||
// protected with internal locks
|
/*
|
||||||
// must get data_lock when resetting the logs
|
Needed to deal properly with cur_log getting closed and re-opened with
|
||||||
MYSQL_LOG relay_log;
|
a different log under our feet
|
||||||
LOG_INFO linfo;
|
|
||||||
IO_CACHE cache_buf,*cur_log;
|
|
||||||
|
|
||||||
/* needed to deal properly with cur_log getting closed and re-opened with
|
|
||||||
a different log under our feet
|
|
||||||
*/
|
*/
|
||||||
int cur_log_init_count;
|
int cur_log_init_count;
|
||||||
|
|
||||||
volatile bool abort_slave, slave_running;
|
volatile bool abort_slave, slave_running;
|
||||||
// needed for problems when slave stops and
|
|
||||||
// we want to restart it skipping one or more events in the master log that
|
/*
|
||||||
// have caused errors, and have been manually applied by DBA already
|
Needed for problems when slave stops and we want to restart it
|
||||||
|
skipping one or more events in the master log that have caused
|
||||||
|
errors, and have been manually applied by DBA already.
|
||||||
|
*/
|
||||||
volatile uint32 slave_skip_counter;
|
volatile uint32 slave_skip_counter;
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
int events_till_abort;
|
int events_till_abort;
|
||||||
@ -168,13 +183,15 @@ typedef struct st_relay_log_info
|
|||||||
relay_log_pos += val+pending;
|
relay_log_pos += val+pending;
|
||||||
pending = 0;
|
pending = 0;
|
||||||
if (log_pos)
|
if (log_pos)
|
||||||
master_log_pos = log_pos+val;
|
master_log_pos = log_pos+ val;
|
||||||
pthread_cond_broadcast(&data_cond);
|
pthread_cond_broadcast(&data_cond);
|
||||||
if (!skip_lock)
|
if (!skip_lock)
|
||||||
pthread_mutex_unlock(&data_lock);
|
pthread_mutex_unlock(&data_lock);
|
||||||
}
|
}
|
||||||
// thread safe read of position - not needed if we are in the slave thread,
|
/*
|
||||||
// but required otherwise
|
thread safe read of position - not needed if we are in the slave thread,
|
||||||
|
but required otherwise
|
||||||
|
*/
|
||||||
inline void read_pos(ulonglong& var)
|
inline void read_pos(ulonglong& var)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&data_lock);
|
pthread_mutex_lock(&data_lock);
|
||||||
@ -185,12 +202,17 @@ typedef struct st_relay_log_info
|
|||||||
int wait_for_pos(THD* thd, String* log_name, ulonglong log_pos);
|
int wait_for_pos(THD* thd, String* log_name, ulonglong log_pos);
|
||||||
} RELAY_LOG_INFO;
|
} RELAY_LOG_INFO;
|
||||||
|
|
||||||
// repopen_relay_log() is called when we notice that the current "hot" log
|
/*
|
||||||
// got rotated under our feet
|
repopen_relay_log() is called when we notice that the current "hot" log
|
||||||
|
got rotated under our feet
|
||||||
|
*/
|
||||||
|
|
||||||
IO_CACHE* reopen_relay_log(RELAY_LOG_INFO* rli, const char** errmsg);
|
IO_CACHE* reopen_relay_log(RELAY_LOG_INFO* rli, const char** errmsg);
|
||||||
Log_event* next_event(RELAY_LOG_INFO* rli);
|
Log_event* next_event(RELAY_LOG_INFO* rli);
|
||||||
|
|
||||||
/* st_master_info contains information about how to connect to a master,
|
|
||||||
|
/*
|
||||||
|
st_master_info contains information about how to connect to a master,
|
||||||
current master log name, and current log offset, as well as misc
|
current master log name, and current log offset, as well as misc
|
||||||
control variables
|
control variables
|
||||||
|
|
||||||
@ -214,14 +236,14 @@ Log_event* next_event(RELAY_LOG_INFO* rli);
|
|||||||
flush_master_info() is required.
|
flush_master_info() is required.
|
||||||
|
|
||||||
To clean up, call end_master_info()
|
To clean up, call end_master_info()
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
typedef struct st_master_info
|
typedef struct st_master_info
|
||||||
{
|
{
|
||||||
char master_log_name[FN_REFLEN];
|
char master_log_name[FN_REFLEN];
|
||||||
|
|
||||||
ulonglong master_log_pos;
|
my_off_t master_log_pos;
|
||||||
File fd;
|
File fd;
|
||||||
IO_CACHE file;
|
IO_CACHE file;
|
||||||
|
|
||||||
@ -229,24 +251,22 @@ typedef struct st_master_info
|
|||||||
char host[HOSTNAME_LENGTH+1];
|
char host[HOSTNAME_LENGTH+1];
|
||||||
char user[USERNAME_LENGTH+1];
|
char user[USERNAME_LENGTH+1];
|
||||||
char password[HASH_PASSWORD_LENGTH+1];
|
char password[HASH_PASSWORD_LENGTH+1];
|
||||||
uint port;
|
|
||||||
uint connect_retry;
|
|
||||||
pthread_mutex_t data_lock,run_lock;
|
pthread_mutex_t data_lock,run_lock;
|
||||||
pthread_cond_t data_cond,start_cond,stop_cond;
|
pthread_cond_t data_cond,start_cond,stop_cond;
|
||||||
bool inited;
|
THD *io_thd;
|
||||||
bool old_format; /* master binlog is in 3.23 format */
|
|
||||||
RELAY_LOG_INFO rli;
|
RELAY_LOG_INFO rli;
|
||||||
|
uint port;
|
||||||
|
uint connect_retry;
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
int events_till_abort;
|
int events_till_abort;
|
||||||
#endif
|
#endif
|
||||||
|
bool inited;
|
||||||
|
bool old_format; // master binlog is in 3.23 format
|
||||||
volatile bool abort_slave, slave_running;
|
volatile bool abort_slave, slave_running;
|
||||||
|
|
||||||
bool ignore_stop_event;
|
bool ignore_stop_event;
|
||||||
|
|
||||||
THD* io_thd;
|
|
||||||
|
|
||||||
st_master_info():fd(-1),inited(0),
|
st_master_info():fd(-1), io_thd(0), inited(0), old_format(0)
|
||||||
old_format(0),io_thd(0)
|
|
||||||
{
|
{
|
||||||
host[0] = 0; user[0] = 0; password[0] = 0;
|
host[0] = 0; user[0] = 0; password[0] = 0;
|
||||||
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
|
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
|
||||||
@ -267,7 +287,7 @@ typedef struct st_master_info
|
|||||||
|
|
||||||
} MASTER_INFO;
|
} MASTER_INFO;
|
||||||
|
|
||||||
int queue_event(MASTER_INFO* mi,const char* buf,uint event_len);
|
int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len);
|
||||||
|
|
||||||
typedef struct st_table_rule_ent
|
typedef struct st_table_rule_ent
|
||||||
{
|
{
|
||||||
@ -288,10 +308,12 @@ typedef struct st_table_rule_ent
|
|||||||
/* masks for start/stop operations on io and sql slave threads */
|
/* masks for start/stop operations on io and sql slave threads */
|
||||||
#define SLAVE_IO 1
|
#define SLAVE_IO 1
|
||||||
#define SLAVE_SQL 2
|
#define SLAVE_SQL 2
|
||||||
#define SLAVE_FORCE_ALL 4 /* if this is set, if first gives an
|
|
||||||
error, second will be tried. Otherwise,
|
/*
|
||||||
if first fails, we fail
|
If the following is set, if first gives an error, second will be
|
||||||
*/
|
tried. Otherwise, if first fails, we fail.
|
||||||
|
*/
|
||||||
|
#define SLAVE_FORCE_ALL 4
|
||||||
|
|
||||||
int init_slave();
|
int init_slave();
|
||||||
void init_slave_skip_errors(char* arg);
|
void init_slave_skip_errors(char* arg);
|
||||||
@ -307,10 +329,11 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_mutex,
|
|||||||
int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
|
int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
|
||||||
MASTER_INFO* mi, const char* master_info_fname,
|
MASTER_INFO* mi, const char* master_info_fname,
|
||||||
const char* slave_info_fname, int thread_mask);
|
const char* slave_info_fname, int thread_mask);
|
||||||
/* cond_lock is usually same as start_lock. It is needed for the case when
|
/*
|
||||||
start_lock is 0 which happens if start_slave_thread() is called already
|
cond_lock is usually same as start_lock. It is needed for the case when
|
||||||
inside the start_lock section, but at the same time we want a
|
start_lock is 0 which happens if start_slave_thread() is called already
|
||||||
pthread_cond_wait() on start_cond,start_lock
|
inside the start_lock section, but at the same time we want a
|
||||||
|
pthread_cond_wait() on start_cond,start_lock
|
||||||
*/
|
*/
|
||||||
int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
|
int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
|
||||||
pthread_mutex_t *cond_lock,
|
pthread_mutex_t *cond_lock,
|
||||||
@ -318,24 +341,26 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
|
|||||||
volatile bool* slave_running,
|
volatile bool* slave_running,
|
||||||
MASTER_INFO* mi);
|
MASTER_INFO* mi);
|
||||||
|
|
||||||
|
// If fd is -1, dump to NET
|
||||||
int mysql_table_dump(THD* thd, const char* db,
|
int mysql_table_dump(THD* thd, const char* db,
|
||||||
const char* tbl_name, int fd = -1);
|
const char* tbl_name, int fd = -1);
|
||||||
// if fd is -1, dump to NET
|
|
||||||
|
|
||||||
int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
|
|
||||||
MASTER_INFO* mi, MYSQL* mysql);
|
|
||||||
// retrieve non-exitent table from master
|
// retrieve non-exitent table from master
|
||||||
|
int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
|
||||||
|
MASTER_INFO* mi, MYSQL* mysql);
|
||||||
|
|
||||||
int show_master_info(THD* thd, MASTER_INFO* mi);
|
int show_master_info(THD* thd, MASTER_INFO* mi);
|
||||||
int show_binlog_info(THD* thd);
|
int show_binlog_info(THD* thd);
|
||||||
|
|
||||||
|
// See if the query uses any tables that should not be replicated
|
||||||
int tables_ok(THD* thd, TABLE_LIST* tables);
|
int tables_ok(THD* thd, TABLE_LIST* tables);
|
||||||
// see if the query uses any tables that should not be replicated
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check to see if the database is ok to operate on with respect to the
|
||||||
|
do and ignore lists - used in replication
|
||||||
|
*/
|
||||||
int db_ok(const char* db, I_List<i_string> &do_list,
|
int db_ok(const char* db, I_List<i_string> &do_list,
|
||||||
I_List<i_string> &ignore_list );
|
I_List<i_string> &ignore_list );
|
||||||
// check to see if the database is ok to operate on with respect to the
|
|
||||||
// do and ignore lists - used in replication
|
|
||||||
|
|
||||||
int add_table_rule(HASH* h, const char* table_spec);
|
int add_table_rule(HASH* h, const char* table_spec);
|
||||||
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
|
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
|
||||||
@ -380,13 +405,11 @@ extern int disconnect_slave_event_count, abort_slave_event_count ;
|
|||||||
// the master variables are defaults read from my.cnf or command line
|
// the master variables are defaults read from my.cnf or command line
|
||||||
extern uint master_port, master_connect_retry, report_port;
|
extern uint master_port, master_connect_retry, report_port;
|
||||||
extern my_string master_user, master_password, master_host,
|
extern my_string master_user, master_password, master_host,
|
||||||
master_info_file, relay_log_info_file, report_user, report_host,
|
master_info_file, relay_log_info_file, report_user, report_host,
|
||||||
report_password;
|
report_password;
|
||||||
|
|
||||||
extern I_List<i_string> replicate_do_db, replicate_ignore_db;
|
extern I_List<i_string> replicate_do_db, replicate_ignore_db;
|
||||||
extern I_List<i_string_pair> replicate_rewrite_db;
|
extern I_List<i_string_pair> replicate_rewrite_db;
|
||||||
extern I_List<THD> threads;
|
extern I_List<THD> threads;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
/* Copyright (C) 2000 MySQL AB
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -110,7 +110,7 @@ static void update_hostname(acl_host_and_ip *host, const char *hostname);
|
|||||||
static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
|
static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
|
||||||
const char *ip);
|
const char *ip);
|
||||||
|
|
||||||
int acl_init(bool dont_read_acl_tables)
|
int acl_init(bool dont_read_acl_tables)
|
||||||
{
|
{
|
||||||
THD *thd;
|
THD *thd;
|
||||||
TABLE_LIST tables[3];
|
TABLE_LIST tables[3];
|
||||||
@ -243,13 +243,16 @@ int acl_init(bool dont_read_acl_tables)
|
|||||||
user.hostname_length=user.host.hostname ? (uint) strlen(user.host.hostname) : 0;
|
user.hostname_length=user.host.hostname ? (uint) strlen(user.host.hostname) : 0;
|
||||||
if (table->fields >=23)
|
if (table->fields >=23)
|
||||||
{
|
{
|
||||||
|
/* Table has new MySQL usage limits */
|
||||||
char *ptr = get_field(&mem, table, 21);
|
char *ptr = get_field(&mem, table, 21);
|
||||||
user.questions=atoi(ptr);
|
user.questions=atoi(ptr);
|
||||||
ptr = get_field(&mem, table, 22);
|
ptr = get_field(&mem, table, 22);
|
||||||
user.updates=atoi(ptr);
|
user.updates=atoi(ptr);
|
||||||
if (user.questions)
|
if (user.questions)
|
||||||
mqh_used=true;
|
mqh_used=1;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
user.questions=user.updates=0;
|
||||||
#ifndef TO_BE_REMOVED
|
#ifndef TO_BE_REMOVED
|
||||||
if (table->fields <= 13)
|
if (table->fields <= 13)
|
||||||
{ // Without grant
|
{ // Without grant
|
||||||
@ -430,15 +433,20 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get master privilges for user (priviliges for all tables). Required to connect */
|
/*
|
||||||
|
Get master privilges for user (priviliges for all tables).
|
||||||
|
Required before connecting to MySQL
|
||||||
|
*/
|
||||||
|
|
||||||
uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
||||||
const char *password,const char *message,char **priv_user,
|
const char *password,const char *message,char **priv_user,
|
||||||
bool old_ver, uint *max)
|
bool old_ver, uint *max_questions)
|
||||||
{
|
{
|
||||||
uint user_access=NO_ACCESS;
|
uint user_access=NO_ACCESS;
|
||||||
*priv_user=(char*) user;
|
*priv_user=(char*) user;
|
||||||
char *ptr=0;
|
char *ptr=0;
|
||||||
|
|
||||||
|
*max_questions=0;
|
||||||
if (!initialized)
|
if (!initialized)
|
||||||
return (uint) ~NO_ACCESS; // If no data allow anything /* purecov: tested */
|
return (uint) ~NO_ACCESS; // If no data allow anything /* purecov: tested */
|
||||||
VOID(pthread_mutex_lock(&acl_cache->lock));
|
VOID(pthread_mutex_lock(&acl_cache->lock));
|
||||||
@ -546,7 +554,7 @@ uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
|||||||
#else /* HAVE_OPENSSL */
|
#else /* HAVE_OPENSSL */
|
||||||
user_access=acl_user->access;
|
user_access=acl_user->access;
|
||||||
#endif /* HAVE_OPENSSL */
|
#endif /* HAVE_OPENSSL */
|
||||||
*max=acl_user->questions;
|
*max_questions=acl_user->questions;
|
||||||
if (!acl_user->user)
|
if (!acl_user->user)
|
||||||
*priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
|
*priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
|
||||||
break;
|
break;
|
||||||
@ -1221,12 +1229,10 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* HAVE_OPENSSL */
|
#endif /* HAVE_OPENSSL */
|
||||||
if (table->fields>=23 && thd->lex.mqh)
|
if (table->fields >= 23 && thd->lex.mqh)
|
||||||
{
|
{
|
||||||
char buff[33];
|
table->field[21]->store((longlong) thd->lex.mqh);
|
||||||
int len =int2str((long)thd->lex.mqh,buff,10) - buff;
|
mqh_used=1;
|
||||||
table->field[21]->store(buff,len);
|
|
||||||
mqh_used=true;
|
|
||||||
}
|
}
|
||||||
if (old_row_exists)
|
if (old_row_exists)
|
||||||
{
|
{
|
||||||
@ -2181,7 +2187,7 @@ int grant_init (void)
|
|||||||
delete thd;
|
delete thd;
|
||||||
DBUG_RETURN(0); // Empty table is ok!
|
DBUG_RETURN(0); // Empty table is ok!
|
||||||
}
|
}
|
||||||
grant_option = TRUE;
|
grant_option= TRUE;
|
||||||
t_table->file->index_end();
|
t_table->file->index_end();
|
||||||
|
|
||||||
MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
|
MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
|
||||||
|
@ -612,8 +612,6 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* move table first in unused links */
|
/* move table first in unused links */
|
||||||
|
|
||||||
static void relink_unused(TABLE *table)
|
static void relink_unused(TABLE *table)
|
||||||
@ -2144,7 +2142,10 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
|
|||||||
THD *in_use;
|
THD *in_use;
|
||||||
table->version=0L; /* Free when thread is ready */
|
table->version=0L; /* Free when thread is ready */
|
||||||
if (!(in_use=table->in_use))
|
if (!(in_use=table->in_use))
|
||||||
|
{
|
||||||
|
DBUG_PRINT("info",("Table was not in use"));
|
||||||
relink_unused(table);
|
relink_unused(table);
|
||||||
|
}
|
||||||
else if (in_use != thd)
|
else if (in_use != thd)
|
||||||
{
|
{
|
||||||
in_use->some_tables_deleted=1;
|
in_use->some_tables_deleted=1;
|
||||||
|
@ -3088,6 +3088,7 @@ my_bool Query_cache::check_integrity(bool not_locked)
|
|||||||
result = 1;
|
result = 1;
|
||||||
break;
|
break;
|
||||||
case Query_cache_block::QUERY:
|
case Query_cache_block::QUERY:
|
||||||
|
{
|
||||||
if (in_list(queries_blocks, block, "query"))
|
if (in_list(queries_blocks, block, "query"))
|
||||||
result = 1;
|
result = 1;
|
||||||
for (TABLE_COUNTER_TYPE j=0; j < block->n_tables; j++)
|
for (TABLE_COUNTER_TYPE j=0; j < block->n_tables; j++)
|
||||||
@ -3102,6 +3103,7 @@ my_bool Query_cache::check_integrity(bool not_locked)
|
|||||||
result = 1;
|
result = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Query_cache_block::RES_INCOMPLETE:
|
case Query_cache_block::RES_INCOMPLETE:
|
||||||
// This type of block can be not lincked yet (in multithread environment)
|
// This type of block can be not lincked yet (in multithread environment)
|
||||||
break;
|
break;
|
||||||
|
@ -370,7 +370,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
ulong slave_proxy_id;
|
ulong slave_proxy_id;
|
||||||
NET* slave_net; // network connection from slave -> m.
|
NET* slave_net; // network connection from slave -> m.
|
||||||
uint32 log_pos;
|
my_off_t log_pos;
|
||||||
|
|
||||||
THD();
|
THD();
|
||||||
~THD();
|
~THD();
|
||||||
|
@ -305,6 +305,8 @@ multi_delete::~multi_delete()
|
|||||||
bool multi_delete::send_data(List<Item> &values)
|
bool multi_delete::send_data(List<Item> &values)
|
||||||
{
|
{
|
||||||
int secure_counter= -1;
|
int secure_counter= -1;
|
||||||
|
DBUG_ENTER("multi_delete::send_data");
|
||||||
|
|
||||||
for (table_being_deleted=delete_tables ;
|
for (table_being_deleted=delete_tables ;
|
||||||
table_being_deleted ;
|
table_being_deleted ;
|
||||||
table_being_deleted=table_being_deleted->next, secure_counter++)
|
table_being_deleted=table_being_deleted->next, secure_counter++)
|
||||||
@ -319,13 +321,14 @@ bool multi_delete::send_data(List<Item> &values)
|
|||||||
|
|
||||||
if (secure_counter < 0)
|
if (secure_counter < 0)
|
||||||
{
|
{
|
||||||
|
/* If this is the table we are scanning */
|
||||||
table->status|= STATUS_DELETED;
|
table->status|= STATUS_DELETED;
|
||||||
if (!(error=table->file->delete_row(table->record[0])))
|
if (!(error=table->file->delete_row(table->record[0])))
|
||||||
deleted++;
|
deleted++;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
table->file->print_error(error,MYF(0));
|
table->file->print_error(error,MYF(0));
|
||||||
return 1;
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -334,21 +337,23 @@ bool multi_delete::send_data(List<Item> &values)
|
|||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
error=-1;
|
error=-1;
|
||||||
return 1;
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void multi_delete::send_error(uint errcode,const char *err)
|
void multi_delete::send_error(uint errcode,const char *err)
|
||||||
{
|
{
|
||||||
|
DBUG_ENTER("multi_delete::send_error");
|
||||||
|
|
||||||
/* First send error what ever it is ... */
|
/* First send error what ever it is ... */
|
||||||
::send_error(&thd->net,errcode,err);
|
::send_error(&thd->net,errcode,err);
|
||||||
|
|
||||||
/* If nothing deleted return */
|
/* If nothing deleted return */
|
||||||
if (!deleted)
|
if (!deleted)
|
||||||
return;
|
DBUG_VOID_RETURN;
|
||||||
|
|
||||||
/* Below can happen when thread is killed early ... */
|
/* Below can happen when thread is killed early ... */
|
||||||
if (!table_being_deleted)
|
if (!table_being_deleted)
|
||||||
@ -364,7 +369,10 @@ void multi_delete::send_error(uint errcode,const char *err)
|
|||||||
table_being_deleted == delete_tables) || !not_trans_safe)
|
table_being_deleted == delete_tables) || !not_trans_safe)
|
||||||
ha_rollback_stmt(thd);
|
ha_rollback_stmt(thd);
|
||||||
else if (do_delete)
|
else if (do_delete)
|
||||||
VOID(do_deletes(true));
|
{
|
||||||
|
VOID(do_deletes(1));
|
||||||
|
}
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -375,7 +383,7 @@ void multi_delete::send_error(uint errcode,const char *err)
|
|||||||
1 error
|
1 error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int multi_delete::do_deletes (bool from_send_error)
|
int multi_delete::do_deletes(bool from_send_error)
|
||||||
{
|
{
|
||||||
int error = 0, counter = 0;
|
int error = 0, counter = 0;
|
||||||
|
|
||||||
@ -432,7 +440,7 @@ bool multi_delete::send_eof()
|
|||||||
thd->proc_info="deleting from reference tables";
|
thd->proc_info="deleting from reference tables";
|
||||||
|
|
||||||
/* Does deletes for the last n - 1 tables, returns 0 if ok */
|
/* Does deletes for the last n - 1 tables, returns 0 if ok */
|
||||||
int error = do_deletes(false); // returns 0 if success
|
int error = do_deletes(0); // returns 0 if success
|
||||||
|
|
||||||
/* reset used flags */
|
/* reset used flags */
|
||||||
thd->proc_info="end";
|
thd->proc_info="end";
|
||||||
|
@ -90,6 +90,7 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok)
|
|||||||
static enum enum_ha_read_modes rkey_to_rnext[]=
|
static enum enum_ha_read_modes rkey_to_rnext[]=
|
||||||
{ RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV };
|
{ RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV };
|
||||||
|
|
||||||
|
|
||||||
int mysql_ha_read(THD *thd, TABLE_LIST *tables,
|
int mysql_ha_read(THD *thd, TABLE_LIST *tables,
|
||||||
enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr,
|
enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr,
|
||||||
enum ha_rkey_function ha_rkey_mode, Item *cond,
|
enum ha_rkey_function ha_rkey_mode, Item *cond,
|
||||||
@ -121,6 +122,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
|
|||||||
List<Item> list;
|
List<Item> list;
|
||||||
list.push_front(new Item_field(NULL,NULL,"*"));
|
list.push_front(new Item_field(NULL,NULL,"*"));
|
||||||
List_iterator<Item> it(list);
|
List_iterator<Item> it(list);
|
||||||
|
uint num_rows;
|
||||||
it++;
|
it++;
|
||||||
|
|
||||||
insert_fields(thd,tables,tables->db,tables->name,&it);
|
insert_fields(thd,tables,tables->db,tables->name,&it);
|
||||||
@ -136,65 +138,64 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
|
|||||||
if (!lock)
|
if (!lock)
|
||||||
goto err0; // mysql_lock_tables() printed error message already
|
goto err0; // mysql_lock_tables() printed error message already
|
||||||
|
|
||||||
for (uint num_rows=0; num_rows < select_limit; )
|
for (num_rows=0; num_rows < select_limit; )
|
||||||
{
|
{
|
||||||
switch(mode)
|
switch(mode) {
|
||||||
|
case RFIRST:
|
||||||
|
err=keyname ?
|
||||||
|
table->file->index_first(table->record[0]) :
|
||||||
|
table->file->rnd_init(1) ||
|
||||||
|
table->file->rnd_next(table->record[0]);
|
||||||
|
mode=RNEXT;
|
||||||
|
break;
|
||||||
|
case RLAST:
|
||||||
|
DBUG_ASSERT(keyname != 0);
|
||||||
|
err=table->file->index_last(table->record[0]);
|
||||||
|
mode=RPREV;
|
||||||
|
break;
|
||||||
|
case RNEXT:
|
||||||
|
err=keyname ?
|
||||||
|
table->file->index_next(table->record[0]) :
|
||||||
|
table->file->rnd_next(table->record[0]);
|
||||||
|
break;
|
||||||
|
case RPREV:
|
||||||
|
DBUG_ASSERT(keyname != 0);
|
||||||
|
err=table->file->index_prev(table->record[0]);
|
||||||
|
break;
|
||||||
|
case RKEY:
|
||||||
{
|
{
|
||||||
case RFIRST:
|
DBUG_ASSERT(keyname != 0);
|
||||||
err=keyname ?
|
KEY *keyinfo=table->key_info+keyno;
|
||||||
table->file->index_first(table->record[0]) :
|
KEY_PART_INFO *key_part=keyinfo->key_part;
|
||||||
table->file->rnd_init(1) ||
|
uint key_len;
|
||||||
table->file->rnd_next(table->record[0]);
|
byte *key;
|
||||||
mode=RNEXT;
|
if (key_expr->elements > keyinfo->key_parts)
|
||||||
break;
|
{
|
||||||
case RLAST:
|
my_printf_error(ER_TOO_MANY_KEY_PARTS,ER(ER_TOO_MANY_KEY_PARTS),
|
||||||
DBUG_ASSERT(keyname != 0);
|
MYF(0),keyinfo->key_parts);
|
||||||
err=table->file->index_last(table->record[0]);
|
goto err;
|
||||||
mode=RPREV;
|
}
|
||||||
break;
|
List_iterator_fast<Item> it_ke(*key_expr);
|
||||||
case RNEXT:
|
Item *item;
|
||||||
err=keyname ?
|
for (key_len=0 ; (item=it_ke++) ; key_part++)
|
||||||
table->file->index_next(table->record[0]) :
|
{
|
||||||
table->file->rnd_next(table->record[0]);
|
item->save_in_field(key_part->field);
|
||||||
break;
|
key_len+=key_part->store_length;
|
||||||
case RPREV:
|
}
|
||||||
DBUG_ASSERT(keyname != 0);
|
if (!(key= (byte*) sql_calloc(ALIGN_SIZE(key_len))))
|
||||||
err=table->file->index_prev(table->record[0]);
|
{
|
||||||
break;
|
send_error(&thd->net,ER_OUTOFMEMORY);
|
||||||
case RKEY:
|
goto err;
|
||||||
{
|
}
|
||||||
DBUG_ASSERT(keyname != 0);
|
key_copy(key, table, keyno, key_len);
|
||||||
KEY *keyinfo=table->key_info+keyno;
|
err=table->file->index_read(table->record[0],
|
||||||
KEY_PART_INFO *key_part=keyinfo->key_part;
|
key,key_len,ha_rkey_mode);
|
||||||
uint key_len;
|
mode=rkey_to_rnext[(int)ha_rkey_mode];
|
||||||
byte *key;
|
break;
|
||||||
if (key_expr->elements > keyinfo->key_parts)
|
}
|
||||||
{
|
default:
|
||||||
my_printf_error(ER_TOO_MANY_KEY_PARTS,ER(ER_TOO_MANY_KEY_PARTS),
|
send_error(&thd->net,ER_ILLEGAL_HA);
|
||||||
MYF(0),keyinfo->key_parts);
|
goto err;
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
List_iterator_fast<Item> it_ke(*key_expr);
|
|
||||||
Item *item;
|
|
||||||
for (key_len=0 ; (item=it_ke++) ; key_part++)
|
|
||||||
{
|
|
||||||
item->save_in_field(key_part->field);
|
|
||||||
key_len+=key_part->store_length;
|
|
||||||
}
|
|
||||||
if (!(key= (byte*) sql_calloc(ALIGN_SIZE(key_len))))
|
|
||||||
{
|
|
||||||
send_error(&thd->net,ER_OUTOFMEMORY);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
key_copy(key, table, keyno, key_len);
|
|
||||||
err=table->file->index_read(table->record[0],
|
|
||||||
key,key_len,ha_rkey_mode);
|
|
||||||
mode=rkey_to_rnext[(int)ha_rkey_mode];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
send_error(&thd->net,ER_ILLEGAL_HA);
|
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
|
215
sql/sql_parse.cc
215
sql/sql_parse.cc
@ -1,4 +1,4 @@
|
|||||||
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
/* Copyright (C) 2000 MySQL AB
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -55,7 +55,9 @@ extern "C" pthread_mutex_t THR_LOCK_keycache;
|
|||||||
extern "C" int gethostname(char *name, int namelen);
|
extern "C" int gethostname(char *name, int namelen);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int check_for_max_user_connections(const char *user, const char *host, uint max);
|
static int check_for_max_user_connections(const char *user, const char *host, uint max_questions);
|
||||||
|
static bool check_mqh(THD *thd, const char *user, const char *host,
|
||||||
|
uint max_questions);
|
||||||
static void decrease_user_connections(const char *user, const char *host);
|
static void decrease_user_connections(const char *user, const char *host);
|
||||||
static bool check_db_used(THD *thd,TABLE_LIST *tables);
|
static bool check_db_used(THD *thd,TABLE_LIST *tables);
|
||||||
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
|
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
|
||||||
@ -121,101 +123,22 @@ extern pthread_mutex_t LOCK_user_conn;
|
|||||||
|
|
||||||
struct user_conn {
|
struct user_conn {
|
||||||
char *user;
|
char *user;
|
||||||
uint len, connections, questions, max;
|
uint len, connections, questions, max_questions;
|
||||||
time_t intime;
|
time_t intime;
|
||||||
};
|
};
|
||||||
|
|
||||||
static byte* get_key_conn(user_conn *buff, uint *length,
|
|
||||||
my_bool not_used __attribute__((unused)))
|
|
||||||
{
|
|
||||||
*length=buff->len;
|
|
||||||
return (byte*) buff->user;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DEF_USER_COUNT 50
|
|
||||||
|
|
||||||
static void free_user(struct user_conn *uc)
|
|
||||||
{
|
|
||||||
my_free((char*) uc,MYF(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Check if maximum queries per hour limit has been reached
|
Check if user is ok
|
||||||
** returns 0 if OK.
|
Updates:
|
||||||
*/
|
thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
|
||||||
|
|
||||||
static bool check_mqh(THD *thd, const char *user, const char *host,uint max)
|
|
||||||
{
|
|
||||||
uint temp_len;
|
|
||||||
char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
|
|
||||||
struct user_conn *uc;
|
|
||||||
if (!user)
|
|
||||||
user="";
|
|
||||||
if (!host)
|
|
||||||
host="";
|
|
||||||
temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
|
|
||||||
NullS) - temp_user);
|
|
||||||
//This would be MUCH faster if there was already temp_user made in THD !!! May I ??
|
|
||||||
(void) pthread_mutex_lock(&LOCK_user_conn);
|
|
||||||
uc = (struct user_conn *) hash_search(&hash_user_connections,
|
|
||||||
(byte*) temp_user, temp_len);
|
|
||||||
if (uc) /* user found ; check for no. of queries */
|
|
||||||
{
|
|
||||||
bool my_start = thd->start_time != 0;
|
|
||||||
time_t check_time = (my_start) ? thd->start_time : time(NULL);
|
|
||||||
if (check_time - uc->intime >= 3600)
|
|
||||||
{
|
|
||||||
uc->questions=(uint)my_start;
|
|
||||||
uc->intime=check_time;
|
|
||||||
}
|
|
||||||
else if (uc->max && ++(uc->questions) > uc->max)
|
|
||||||
{
|
|
||||||
(void) pthread_mutex_unlock(&LOCK_user_conn);
|
|
||||||
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); // change this to appropriate message
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
struct user_conn *uc= ((struct user_conn*)
|
|
||||||
my_malloc(sizeof(struct user_conn) + temp_len+1,
|
|
||||||
MYF(MY_WME)));
|
|
||||||
if (!uc)
|
|
||||||
{
|
|
||||||
send_error(¤t_thd->net, 0, NullS); // Out of memory
|
|
||||||
(void) pthread_mutex_unlock(&LOCK_user_conn);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
uc->user=(char*) (uc+1);
|
|
||||||
memcpy(uc->user,temp_user,temp_len+1);
|
|
||||||
uc->len = temp_len;
|
|
||||||
uc->connections = 1;
|
|
||||||
uc->questions=0;
|
|
||||||
uc->max=max;
|
|
||||||
uc->intime=current_thd->thr_create_time;
|
|
||||||
if (hash_insert(&hash_user_connections, (byte*) uc))
|
|
||||||
{
|
|
||||||
my_free((char*) uc,0);
|
|
||||||
send_error(¤t_thd->net, 0, NullS); // Out of memory
|
|
||||||
(void) pthread_mutex_unlock(&LOCK_user_conn);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(void) pthread_mutex_unlock(&LOCK_user_conn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Check if user is ok
|
|
||||||
** Updates:
|
|
||||||
** thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool check_user(THD *thd,enum_server_command command, const char *user,
|
static bool check_user(THD *thd,enum_server_command command, const char *user,
|
||||||
const char *passwd, const char *db, bool check_count)
|
const char *passwd, const char *db, bool check_count)
|
||||||
{
|
{
|
||||||
NET *net= &thd->net;
|
NET *net= &thd->net;
|
||||||
uint max=0;
|
uint max_questions=0;
|
||||||
thd->db=0;
|
thd->db=0;
|
||||||
thd->db_length=0;
|
thd->db_length=0;
|
||||||
|
|
||||||
@ -228,7 +151,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
|
|||||||
passwd, thd->scramble, &thd->priv_user,
|
passwd, thd->scramble, &thd->priv_user,
|
||||||
protocol_version == 9 ||
|
protocol_version == 9 ||
|
||||||
!(thd->client_capabilities &
|
!(thd->client_capabilities &
|
||||||
CLIENT_LONG_PASSWORD),&max);
|
CLIENT_LONG_PASSWORD),&max_questions);
|
||||||
DBUG_PRINT("info",
|
DBUG_PRINT("info",
|
||||||
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
|
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
|
||||||
thd->client_capabilities, thd->max_packet_length,
|
thd->client_capabilities, thd->max_packet_length,
|
||||||
@ -259,8 +182,6 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
|
|||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mqh_used && max && check_mqh(thd,user,thd->host,max))
|
|
||||||
return -1;
|
|
||||||
mysql_log.write(thd,command,
|
mysql_log.write(thd,command,
|
||||||
(thd->priv_user == thd->user ?
|
(thd->priv_user == thd->user ?
|
||||||
(char*) "%s@%s on %s" :
|
(char*) "%s@%s on %s" :
|
||||||
@ -269,8 +190,11 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
|
|||||||
thd->host_or_ip,
|
thd->host_or_ip,
|
||||||
db ? db : (char*) "");
|
db ? db : (char*) "");
|
||||||
thd->db_access=0;
|
thd->db_access=0;
|
||||||
|
/* Don't allow user to connect if he has done too many queries */
|
||||||
|
if (max_questions && check_mqh(thd,user,thd->host_or_ip,max_questions))
|
||||||
|
return -1;
|
||||||
if (max_user_connections &&
|
if (max_user_connections &&
|
||||||
check_for_max_user_connections(user, thd->host, max))
|
check_for_max_user_connections(user, thd->host, max_questions))
|
||||||
return -1;
|
return -1;
|
||||||
if (db && db[0])
|
if (db && db[0])
|
||||||
{
|
{
|
||||||
@ -285,30 +209,40 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** check for maximum allowable user connections
|
Check for maximum allowable user connections, if the mysqld server is
|
||||||
** if mysql server is started with corresponding
|
started with corresponding variable that is greater then 0.
|
||||||
** variable that is greater then 0
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static byte* get_key_conn(user_conn *buff, uint *length,
|
||||||
|
my_bool not_used __attribute__((unused)))
|
||||||
|
{
|
||||||
|
*length=buff->len;
|
||||||
|
return (byte*) buff->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void free_user(struct user_conn *uc)
|
||||||
|
{
|
||||||
|
my_free((char*) uc,MYF(0));
|
||||||
|
}
|
||||||
|
|
||||||
void init_max_user_conn(void)
|
void init_max_user_conn(void)
|
||||||
{
|
{
|
||||||
(void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0,
|
(void) hash_init(&hash_user_connections,max_connections,0,0,
|
||||||
(hash_get_key) get_key_conn, (void (*)(void*)) free_user,
|
(hash_get_key) get_key_conn, (void (*)(void*)) free_user,
|
||||||
0);
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int check_for_max_user_connections(const char *user, const char *host, uint max)
|
static int check_for_max_user_connections(const char *user, const char *host,
|
||||||
|
uint max_questions)
|
||||||
{
|
{
|
||||||
int error=1;
|
int error=1;
|
||||||
uint temp_len;
|
uint temp_len;
|
||||||
char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
|
char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
|
||||||
struct user_conn *uc;
|
struct user_conn *uc;
|
||||||
if (!user)
|
|
||||||
user="";
|
|
||||||
if (!host)
|
|
||||||
host="";
|
|
||||||
DBUG_ENTER("check_for_max_user_connections");
|
DBUG_ENTER("check_for_max_user_connections");
|
||||||
|
DBUG_ASSERT(user != 0);
|
||||||
|
DBUG_ASSERT(host != 0);
|
||||||
DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host));
|
DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host));
|
||||||
|
|
||||||
temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
|
temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
|
||||||
@ -341,7 +275,7 @@ static int check_for_max_user_connections(const char *user, const char *host, ui
|
|||||||
uc->len = temp_len;
|
uc->len = temp_len;
|
||||||
uc->connections = 1;
|
uc->connections = 1;
|
||||||
uc->questions=0;
|
uc->questions=0;
|
||||||
uc->max=max;
|
uc->max_questions=max_questions;
|
||||||
uc->intime=current_thd->thr_create_time;
|
uc->intime=current_thd->thr_create_time;
|
||||||
if (hash_insert(&hash_user_connections, (byte*) uc))
|
if (hash_insert(&hash_user_connections, (byte*) uc))
|
||||||
{
|
{
|
||||||
@ -397,9 +331,82 @@ void free_max_user_conn(void)
|
|||||||
hash_free(&hash_user_connections);
|
hash_free(&hash_user_connections);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** check connnetion and get priviliges
|
Check if maximum queries per hour limit has been reached
|
||||||
** returns 0 on ok, -1 < if error is given > 0 on error.
|
returns 0 if OK.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool check_mqh(THD *thd, const char *user, const char *host,
|
||||||
|
uint max_questions)
|
||||||
|
{
|
||||||
|
uint temp_len;
|
||||||
|
char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
|
||||||
|
struct user_conn *uc;
|
||||||
|
bool error=0;
|
||||||
|
|
||||||
|
DBUG_ASSERT(user != 0);
|
||||||
|
DBUG_ASSERT(host != 0);
|
||||||
|
|
||||||
|
/* TODO: Add username + host to THD for faster execution */
|
||||||
|
temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user)-1, user, "@", host,
|
||||||
|
NullS) - temp_user);
|
||||||
|
(void) pthread_mutex_lock(&LOCK_user_conn);
|
||||||
|
uc = (struct user_conn *) hash_search(&hash_user_connections,
|
||||||
|
(byte*) temp_user, temp_len);
|
||||||
|
if (uc)
|
||||||
|
{
|
||||||
|
/* user found ; check for no. of queries */
|
||||||
|
bool my_start = thd->start_time != 0;
|
||||||
|
time_t check_time = (my_start) ? thd->start_time : time(NULL);
|
||||||
|
if (check_time - uc->intime >= 3600)
|
||||||
|
{
|
||||||
|
uc->questions=(uint) my_start;
|
||||||
|
uc->intime=check_time;
|
||||||
|
}
|
||||||
|
else if (uc->max_questions && ++(uc->questions) > uc->max_questions)
|
||||||
|
{
|
||||||
|
net_printf(&thd->net, ER_USER_LIMIT_REACHED, temp_user, "max_questions",
|
||||||
|
(long) uc->questions);
|
||||||
|
error=1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct user_conn *uc= ((struct user_conn*)
|
||||||
|
my_malloc(sizeof(struct user_conn) + temp_len+1,
|
||||||
|
MYF(MY_WME)));
|
||||||
|
if (!uc)
|
||||||
|
{
|
||||||
|
send_error(¤t_thd->net, 0, NullS); // Out of memory
|
||||||
|
error=1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
uc->user=(char*) (uc+1);
|
||||||
|
memcpy(uc->user,temp_user,temp_len+1);
|
||||||
|
uc->len = temp_len;
|
||||||
|
uc->connections = 1;
|
||||||
|
uc->questions=0;
|
||||||
|
uc->max_questions=max_questions;
|
||||||
|
uc->intime=current_thd->thr_create_time;
|
||||||
|
if (hash_insert(&hash_user_connections, (byte*) uc))
|
||||||
|
{
|
||||||
|
my_free((char*) uc,0);
|
||||||
|
send_error(¤t_thd->net, 0, NullS); // Out of memory
|
||||||
|
error=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
(void) pthread_mutex_unlock(&LOCK_user_conn);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check connnetion and get priviliges
|
||||||
|
Returns 0 on ok, -1 < if error is given > 0 on error.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -408,9 +415,7 @@ check_connections(THD *thd)
|
|||||||
{
|
{
|
||||||
uint connect_errors=0;
|
uint connect_errors=0;
|
||||||
NET *net= &thd->net;
|
NET *net= &thd->net;
|
||||||
/*
|
/* Store the connection details */
|
||||||
** store the connection details
|
|
||||||
*/
|
|
||||||
DBUG_PRINT("info", (("check_connections called by thread %d"),
|
DBUG_PRINT("info", (("check_connections called by thread %d"),
|
||||||
thd->thread_id));
|
thd->thread_id));
|
||||||
DBUG_PRINT("info",("New connection received on %s",
|
DBUG_PRINT("info",("New connection received on %s",
|
||||||
|
@ -129,7 +129,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
|
|||||||
if (!access(name,F_OK))
|
if (!access(name,F_OK))
|
||||||
{
|
{
|
||||||
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),name);
|
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),name);
|
||||||
return ren_table; // This can't be skipped
|
DBUG_RETURN(ren_table); // This can't be skipped
|
||||||
}
|
}
|
||||||
sprintf(name,"%s/%s/%s%s",mysql_data_home,
|
sprintf(name,"%s/%s/%s%s",mysql_data_home,
|
||||||
ren_table->db,ren_table->name,
|
ren_table->db,ren_table->name,
|
||||||
@ -138,7 +138,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
|
|||||||
{
|
{
|
||||||
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
|
||||||
if (!skip_error)
|
if (!skip_error)
|
||||||
return ren_table;
|
DBUG_RETURN(ren_table);
|
||||||
}
|
}
|
||||||
else if (mysql_rename_table(table_type,
|
else if (mysql_rename_table(table_type,
|
||||||
ren_table->db, ren_table->name,
|
ren_table->db, ren_table->name,
|
||||||
|
@ -763,7 +763,6 @@ int change_master(THD* thd, MASTER_INFO* mi)
|
|||||||
1 /* wait for start*/,
|
1 /* wait for start*/,
|
||||||
mi,master_info_file,relay_log_info_file,
|
mi,master_info_file,relay_log_info_file,
|
||||||
restart_thread_mask);
|
restart_thread_mask);
|
||||||
err:
|
|
||||||
unlock_slave_threads(mi);
|
unlock_slave_threads(mi);
|
||||||
thd->proc_info = 0;
|
thd->proc_info = 0;
|
||||||
if (error)
|
if (error)
|
||||||
@ -1006,9 +1005,9 @@ int log_loaded_block(IO_CACHE* file)
|
|||||||
|
|
||||||
/* file->request_pos contains position where we started last read */
|
/* file->request_pos contains position where we started last read */
|
||||||
char* buffer = (char*) file->request_pos;
|
char* buffer = (char*) file->request_pos;
|
||||||
if (!(block_len = file->read_end - buffer))
|
if (!(block_len = (char*) file->read_end - (char*) buffer))
|
||||||
return 0;
|
return 0;
|
||||||
lf_info = (LOAD_FILE_INFO*)file->arg;
|
lf_info = (LOAD_FILE_INFO*) file->arg;
|
||||||
if (lf_info->last_pos_in_file != HA_POS_ERROR &&
|
if (lf_info->last_pos_in_file != HA_POS_ERROR &&
|
||||||
lf_info->last_pos_in_file >= file->pos_in_file)
|
lf_info->last_pos_in_file >= file->pos_in_file)
|
||||||
return 0;
|
return 0;
|
||||||
@ -1030,5 +1029,3 @@ int log_loaded_block(IO_CACHE* file)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
|||||||
ulong select_options,select_result *result)
|
ulong select_options,select_result *result)
|
||||||
{
|
{
|
||||||
TABLE *tmp_table;
|
TABLE *tmp_table;
|
||||||
int error, tmp_error, tmp;
|
int error, tmp_error;
|
||||||
bool need_tmp,hidden_group_fields;
|
bool need_tmp,hidden_group_fields;
|
||||||
bool simple_order,simple_group,no_order, skip_sort_order;
|
bool simple_order,simple_group,no_order, skip_sort_order;
|
||||||
Item::cond_result cond_value;
|
Item::cond_result cond_value;
|
||||||
|
@ -708,7 +708,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
|
|||||||
|
|
||||||
/* Null flag */
|
/* Null flag */
|
||||||
uint flags= key_part->field ? key_part->field->flags : 0;
|
uint flags= key_part->field ? key_part->field->flags : 0;
|
||||||
char *pos=(byte*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
|
char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
|
||||||
net_store_data(packet,convert,(const char*) pos);
|
net_store_data(packet,convert,(const char*) pos);
|
||||||
net_store_data(packet,convert,table->file->index_type(i));
|
net_store_data(packet,convert,table->file->index_type(i));
|
||||||
/* Comment */
|
/* Comment */
|
||||||
|
@ -613,10 +613,12 @@ bool multi_update::send_data(List<Item> &values)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Here I insert into each temporary table
|
// Here we insert into each temporary table
|
||||||
values_by_table.push_front(new Item_string(table->file->ref,table->file->ref_length));
|
values_by_table.push_front(new Item_string((char*) table->file->ref,
|
||||||
|
table->file->ref_length));
|
||||||
fill_record(tmp_tables[secure_counter]->field,values_by_table);
|
fill_record(tmp_tables[secure_counter]->field,values_by_table);
|
||||||
error= write_record(tmp_tables[secure_counter],&(infos[secure_counter]));
|
error= write_record(tmp_tables[secure_counter],
|
||||||
|
&(infos[secure_counter]));
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
error=-1;
|
error=-1;
|
||||||
@ -661,7 +663,8 @@ int multi_update::do_updates (bool from_send_error)
|
|||||||
{
|
{
|
||||||
int error = 0, counter = 0;
|
int error = 0, counter = 0;
|
||||||
|
|
||||||
if (num_updated == 1) return 0;
|
if (num_updated == 1)
|
||||||
|
return 0;
|
||||||
if (from_send_error)
|
if (from_send_error)
|
||||||
{
|
{
|
||||||
/* Found out table number for 'table_being_updated' */
|
/* Found out table number for 'table_being_updated' */
|
||||||
@ -690,7 +693,7 @@ int multi_update::do_updates (bool from_send_error)
|
|||||||
}
|
}
|
||||||
List<Item> list;
|
List<Item> list;
|
||||||
Field **ptr=tmp_table->field,*field;
|
Field **ptr=tmp_table->field,*field;
|
||||||
// This is supposed to be something like insert_fields
|
// This is supposed to be something like insert_fields
|
||||||
thd->used_tables|=tmp_table->map;
|
thd->used_tables|=tmp_table->map;
|
||||||
while ((field = *ptr++))
|
while ((field = *ptr++))
|
||||||
{
|
{
|
||||||
@ -709,12 +712,14 @@ int multi_update::do_updates (bool from_send_error)
|
|||||||
(!thd->killed || from_send_error || not_trans_safe))
|
(!thd->killed || from_send_error || not_trans_safe))
|
||||||
{
|
{
|
||||||
found++;
|
found++;
|
||||||
error= table->file->rnd_pos(table->record[0], (*(tmp_table->field))->ptr);
|
error= table->file->rnd_pos(table->record[0],
|
||||||
|
(byte*) (*(tmp_table->field))->ptr);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
table->status|= STATUS_UPDATED;
|
table->status|= STATUS_UPDATED;
|
||||||
store_record(table,1);
|
store_record(table,1);
|
||||||
error= fill_record(*fields_by_tables[counter + 1],list) /*|| compare_record(table, query_id)*/ ||
|
error= fill_record(*fields_by_tables[counter + 1],list) ||
|
||||||
|
/* compare_record(table, query_id) || */
|
||||||
table->file->update_row(table->record[1],table->record[0]);
|
table->file->update_row(table->record[1],table->record[0]);
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
@ -731,40 +736,47 @@ int multi_update::do_updates (bool from_send_error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* out: 1 if error, 0 if success */
|
||||||
|
|
||||||
bool multi_update::send_eof()
|
bool multi_update::send_eof()
|
||||||
{
|
{
|
||||||
thd->proc_info="updating the reference tables"; /* out: 1 if error, 0 if success */
|
thd->proc_info="updating the reference tables";
|
||||||
|
|
||||||
/* Does updates for the last n - 1 tables, returns 0 if ok */
|
/* Does updates for the last n - 1 tables, returns 0 if ok */
|
||||||
int error = do_updates(false); /* do_updates returns 0 if success */
|
int error = do_updates(false); /* do_updates returns 0 if success */
|
||||||
|
|
||||||
/* reset used flags */
|
/* reset used flags */
|
||||||
// update_tables->table->no_keyread=0;
|
#ifndef NOT_USED
|
||||||
if (error == -1) error = 0;
|
update_tables->table->no_keyread=0;
|
||||||
|
#endif
|
||||||
|
if (error == -1)
|
||||||
|
error = 0;
|
||||||
thd->proc_info="end";
|
thd->proc_info="end";
|
||||||
if (error)
|
if (error)
|
||||||
send_error(error,"An error occured in multi-table update");
|
send_error(error,"An error occured in multi-table update");
|
||||||
|
|
||||||
/* Write the SQL statement to the binlog if we updated
|
/*
|
||||||
rows and we succeeded, or also in an error case when there
|
Write the SQL statement to the binlog if we updated
|
||||||
was a non-transaction-safe table involved, since
|
rows and we succeeded, or also in an error case when there
|
||||||
modifications in it cannot be rolled back. */
|
was a non-transaction-safe table involved, since
|
||||||
|
modifications in it cannot be rolled back.
|
||||||
|
*/
|
||||||
|
|
||||||
if (updated || not_trans_safe)
|
if (updated || not_trans_safe)
|
||||||
{
|
{
|
||||||
mysql_update_log.write(thd,thd->query,thd->query_length);
|
mysql_update_log.write(thd,thd->query,thd->query_length);
|
||||||
Query_log_event qinfo(thd, thd->query);
|
Query_log_event qinfo(thd, thd->query);
|
||||||
|
|
||||||
/* mysql_bin_log is not open if binlogging or replication
|
/*
|
||||||
is not used */
|
mysql_bin_log is not open if binlogging or replication
|
||||||
|
is not used
|
||||||
|
*/
|
||||||
|
|
||||||
if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) &&
|
if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) &&
|
||||||
!not_trans_safe)
|
!not_trans_safe)
|
||||||
error=1; /* Log write failed: roll back
|
error=1; /* Log write failed: roll back the SQL statement */
|
||||||
the SQL statement */
|
|
||||||
|
|
||||||
/* Commit or rollback the current SQL statement */
|
/* Commit or rollback the current SQL statement */
|
||||||
|
|
||||||
VOID(ha_autocommit_or_rollback(thd,error > 0));
|
VOID(ha_autocommit_or_rollback(thd,error > 0));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -777,8 +789,8 @@ bool multi_update::send_eof()
|
|||||||
if (updated)
|
if (updated)
|
||||||
query_cache.invalidate(update_tables);
|
query_cache.invalidate(update_tables);
|
||||||
::send_ok(&thd->net,
|
::send_ok(&thd->net,
|
||||||
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
|
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
|
||||||
thd->insert_id_used ? thd->insert_id() : 0L,buff);
|
thd->insert_id_used ? thd->insert_id() : 0L,buff);
|
||||||
}
|
}
|
||||||
thd->count_cuted_fields=0;
|
thd->count_cuted_fields=0;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -577,7 +577,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||||||
opt_outer table_list table_name opt_option opt_place opt_low_priority
|
opt_outer table_list table_name opt_option opt_place opt_low_priority
|
||||||
opt_attribute opt_attribute_list attribute column_list column_list_id
|
opt_attribute opt_attribute_list attribute column_list column_list_id
|
||||||
opt_column_list grant_privileges opt_table user_list grant_option
|
opt_column_list grant_privileges opt_table user_list grant_option
|
||||||
grant_privilege grant_privilege_list mqh_option
|
grant_privilege grant_privilege_list
|
||||||
flush_options flush_option insert_lock_option replace_lock_option
|
flush_options flush_option insert_lock_option replace_lock_option
|
||||||
equal optional_braces opt_key_definition key_usage_list2
|
equal optional_braces opt_key_definition key_usage_list2
|
||||||
opt_mi_check_type opt_to mi_check_types normal_join
|
opt_mi_check_type opt_to mi_check_types normal_join
|
||||||
@ -3395,7 +3395,7 @@ grant:
|
|||||||
lex->mqh=0;
|
lex->mqh=0;
|
||||||
}
|
}
|
||||||
grant_privileges ON opt_table TO_SYM user_list
|
grant_privileges ON opt_table TO_SYM user_list
|
||||||
require_clause grant_option mqh_option
|
require_clause grant_options
|
||||||
|
|
||||||
grant_privileges:
|
grant_privileges:
|
||||||
grant_privilege_list {}
|
grant_privilege_list {}
|
||||||
@ -3582,17 +3582,19 @@ require_clause: /* empty */
|
|||||||
Lex->ssl_type=SSL_TYPE_X509;
|
Lex->ssl_type=SSL_TYPE_X509;
|
||||||
}
|
}
|
||||||
|
|
||||||
grant_option:
|
grant_options:
|
||||||
/* empty */ {}
|
/* empty */ {}
|
||||||
| WITH GRANT OPTION { Lex->grant |= GRANT_ACL;}
|
| WITH grant_option_list
|
||||||
|
|
||||||
mqh_option:
|
grant_option_list:
|
||||||
/* empty */ {}
|
grant_option_list grant_option {}
|
||||||
| AND WITH MAX_QUERIES_PER_HOUR EQ NUM
|
| grant_option {}
|
||||||
{
|
|
||||||
Lex->mqh=atoi($5.str);
|
grant_option:
|
||||||
if (Lex->mqh > 65535)
|
GRANT OPTION { Lex->grant |= GRANT_ACL;}
|
||||||
YYABORT;
|
| MAX_QUERIES_PER_HOUR EQ NUM
|
||||||
|
{
|
||||||
|
Lex->mqh=atoi($3.str);
|
||||||
}
|
}
|
||||||
|
|
||||||
begin:
|
begin:
|
||||||
|
@ -49,7 +49,8 @@
|
|||||||
X >= 'a' && X <= 'z' ? X-'a'+10 :\
|
X >= 'a' && X <= 'z' ? X-'a'+10 :\
|
||||||
'\177')
|
'\177')
|
||||||
|
|
||||||
char *str2int(register const char *src, register int radix, long int lower, long int upper, long int *val)
|
char *str2int(register const char *src, register int radix, long int lower,
|
||||||
|
long int upper, long int *val)
|
||||||
{
|
{
|
||||||
int sign; /* is number negative (+1) or positive (-1) */
|
int sign; /* is number negative (+1) or positive (-1) */
|
||||||
int n; /* number of digits yet to be converted */
|
int n; /* number of digits yet to be converted */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user