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,
|
||||
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
|
||||
extension @code{CONCAT()} (in lieu of the standard @code{||} operator).
|
||||
For example:
|
||||
@ -3686,6 +3686,7 @@ For platform-specific bugs, see the sections about compiling and porting.
|
||||
|
||||
@menu
|
||||
* 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 sometime:: Things That Have to be Done Sometime
|
||||
* 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.
|
||||
|
||||
|
||||
@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
|
||||
|
||||
We have now shifted development to MySQL Server 4.0. Most of the basic
|
||||
things we want to have in 4.0 are already done. The target is to quickly
|
||||
implement the rest of the following features and then shift development
|
||||
to MySQL Server 4.1. @xref{MySQL 4.0 In A Nutshell}.
|
||||
We have now in the final stages one the development of the MySQL Server
|
||||
4.0. server. The target is to quickly implement the rest of the
|
||||
following features and then shift development to MySQL Server
|
||||
4.1. @xref{MySQL 4.0 In A Nutshell}.
|
||||
|
||||
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}.
|
||||
|
||||
This section lists features not yet implemented in the current
|
||||
version of MySQL Server 4.0, which will however be implemented in
|
||||
later versions of MySQL 4.0. This being very volatile information,
|
||||
please consider this list valid only if you are reading it from
|
||||
the MySQL web site (@uref{http://www.mysql.com/}).
|
||||
This section lists features not yet implemented in the current version
|
||||
of MySQL Server 4.0, which will however be implemented in later versions
|
||||
of MySQL 4.0. This being very volatile information, please consider this
|
||||
list valid only if you are reading it from the MySQL web site
|
||||
(@uref{http://www.mysql.com/}).
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Allow users to change startup options without taking down the server.
|
||||
@item
|
||||
Fail safe replication.
|
||||
Better command line argument handling.
|
||||
@item
|
||||
New key cache
|
||||
New key cache, which will give better performance when using many threads.
|
||||
@item
|
||||
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
|
||||
@ -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.
|
||||
|
||||
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
|
||||
Replication should work with @code{RAND()} and user variables @code{@@var}.
|
||||
@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
|
||||
master.
|
||||
@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.
|
||||
To do this, we need to update the threads record cache when we update
|
||||
the @code{.MYD} file.
|
||||
@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
|
||||
at once and not only strings. This will enable users to use the translated
|
||||
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
|
||||
corrupt the table.
|
||||
@item
|
||||
@code{SET SQL_DEFAULT_TABLE_TYPE=[MyISAM | INNODB | BDB | HEAP]}.
|
||||
@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
|
||||
A faster, smaller embedded MySQL library. (Compatible with the old one)
|
||||
@item
|
||||
Subqueries.
|
||||
@code{SELECT id FROM t WHERE grp IN (SELECT grp FROM g WHERE u > 100)}
|
||||
Stable openssl support. (MySQL 4.0 supports rudimentary, not 100 % tested
|
||||
support for openssl).
|
||||
@item
|
||||
Atomic multi-table updates, eg @code{update items,month set
|
||||
items.price=month.price where items.id=month.id;};
|
||||
Add support for sorting on @code{UNICODE}.
|
||||
@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.
|
||||
Character set casts and syntax for handling multiple character sets.
|
||||
@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
|
||||
Extend the client/server protocol to support warnings.
|
||||
Help for all commands from the client.
|
||||
@item
|
||||
Add options to the client/server protocol to get progress notes
|
||||
for long running commands.
|
||||
New faster client/server protocol which will support prepared statements,
|
||||
bound parameters and bound result columns, binary transfer of data,
|
||||
warnings...
|
||||
@item
|
||||
Add database and real table name (in case of alias) to the MYSQL_FIELD
|
||||
structure.
|
||||
@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.
|
||||
Add options to the client/server protocol to get progress notes
|
||||
for long running commands.
|
||||
@item
|
||||
Implement @code{RENAME DATABASE}. To make this safe for all table handlers,
|
||||
it should work as follows:
|
||||
@ -3818,16 +3833,45 @@ we do with the @code{RENAME} command.
|
||||
Drop the old database.
|
||||
@end itemize
|
||||
@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)
|
||||
... GROUP BY}.
|
||||
@item
|
||||
Multiple result sets.
|
||||
@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
|
||||
in microseconds.
|
||||
@item
|
||||
@ -3836,6 +3880,8 @@ options like database in use, time and date...
|
||||
@item
|
||||
Link the @code{myisampack} code into the server.
|
||||
@item
|
||||
Port of the MySQL code to QNX.
|
||||
@item
|
||||
Port of the MySQL code to BeOS.
|
||||
@item
|
||||
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
|
||||
a concurrent insert at the end of the file if the file is read-locked.
|
||||
@item
|
||||
Remember @code{FOREIGN} key definitions in the @file{.frm} file.
|
||||
@item
|
||||
Cascading @code{DELETE}
|
||||
@item
|
||||
Server side cursors.
|
||||
@item
|
||||
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
|
||||
without reading results or give a nice error message when one does this.
|
||||
@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.
|
||||
@item
|
||||
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
|
||||
@end example
|
||||
@item
|
||||
Add true @code{VARCHAR} support (There is already support for this in
|
||||
@code{MyISAM}).
|
||||
@item
|
||||
Automatic output from @code{mysql} to Netscape.
|
||||
@item
|
||||
@code{LOCK DATABASES}. (with various options)
|
||||
@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{Field_decimal::store(const char *from,uint len)} must be recoded
|
||||
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
|
||||
should be implemented.
|
||||
@item
|
||||
Add support for UNICODE.
|
||||
@item
|
||||
@code{NATURAL JOIN}.
|
||||
@item
|
||||
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
|
||||
values before the update started.
|
||||
@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
|
||||
concurrent inserts.
|
||||
@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
|
||||
@code{-fno-exceptions} option, it is @strong{very important} that you use
|
||||
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:
|
||||
|
||||
@example
|
||||
@ -6969,8 +6999,9 @@ speed of your connection; be patient.
|
||||
@item
|
||||
You will need GNU @code{autoconf 2.13}, @code{automake 1.4},
|
||||
@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
|
||||
have @code{libtool} installed!
|
||||
@ -8100,12 +8131,24 @@ than it had in 3.23.
|
||||
@item
|
||||
@code{SIGNED} is a reserved word.
|
||||
@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,
|
||||
you need to rebuild them with @code{ALTER TABLE table_name TYPE=MyISAM},
|
||||
@strong{even} if they are of @code{MyISAM} type.
|
||||
@item
|
||||
@code{LOCATE()} and @code{INSTR()} are case sensitive if neither
|
||||
argument is a binary string.
|
||||
@code{LOCATE()} and @code{INSTR()} are case sensitive if one of the
|
||||
arguments is a binary string.
|
||||
@item
|
||||
@code{HEX(string)} now returns the characters in string converted to
|
||||
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]]
|
||||
[ISSUER issuer [AND]]
|
||||
[SUBJECT subject]]
|
||||
[WITH GRANT OPTION]
|
||||
[WITH [GRANT OPTION | MAX_QUERIES_PER_HOUR=#]]
|
||||
|
||||
REVOKE priv_type [(column_list)] [, priv_type [(column_list)] ...]
|
||||
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
|
||||
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;
|
||||
the @strong{grant} privilege allows you to give away only those privileges
|
||||
you possess.
|
||||
@ -28068,6 +28117,10 @@ that are optional.
|
||||
Note that if you specify @code{ZEROFILL} for a column, MySQL will
|
||||
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
|
||||
@tindex TINYINT
|
||||
@item TINYINT[(M)] [UNSIGNED] [ZEROFILL]
|
||||
@ -30841,9 +30894,13 @@ make string comparison even more flexible.
|
||||
@node Arithmetic functions, Mathematical functions, Numeric Functions, Numeric Functions
|
||||
@subsubsection Arithmetic Operations
|
||||
|
||||
@cindex operators, cast
|
||||
The usual arithmetic operators are available. Note that in the case of
|
||||
@samp{-}, @samp{+}, and @samp{*}, the result is calculated with
|
||||
@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 arithmetic expressions
|
||||
@ -30879,8 +30936,9 @@ mysql> select 18014398509481984*18014398509481984;
|
||||
-> 0
|
||||
@end example
|
||||
|
||||
The result of the last expression is incorrect because the result of the integer
|
||||
multiplication exceeds the 64-bit range of @code{BIGINT} calculations.
|
||||
The result of the last expression is incorrect because the result of the
|
||||
integer multiplication exceeds the 64-bit range of @code{BIGINT}
|
||||
calculations.
|
||||
|
||||
@findex / (division)
|
||||
@findex division (/)
|
||||
@ -31903,10 +31961,10 @@ mysql> select 1+'1';
|
||||
|
||||
MySQL supports arithmetic with both signed and unsigned 64 bit values.
|
||||
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
|
||||
override this by using the @code{SIGNED} and @code{UNSIGNED} cast
|
||||
operators, which will cast the operation to signed respective unsigned
|
||||
64 bit integer.
|
||||
operands are @code{unsigned integer}, then the result will be unsigned.
|
||||
You can override this by using the @code{SIGNED} and @code{UNSIGNED}
|
||||
cast operators, which will cast the operation to signed respective
|
||||
unsigned 64 bit integer.
|
||||
|
||||
@example
|
||||
mysql> select CAST(1-2 AS UNSIGNED)
|
||||
@ -31915,8 +31973,33 @@ mysql select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED);
|
||||
-> -1
|
||||
@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 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
|
||||
@subsection Other Functions
|
||||
|
||||
@ -31941,12 +32024,14 @@ these operators have a maximum range of 64 bits.
|
||||
@findex | (bitwise OR)
|
||||
@findex OR, bitwise
|
||||
@item |
|
||||
Bitwise OR:
|
||||
Bitwise OR
|
||||
@example
|
||||
mysql> select 29 | 15;
|
||||
-> 31
|
||||
@end example
|
||||
|
||||
The result is an unsigned 64 bit integer.
|
||||
|
||||
@findex & (bitwise AND)
|
||||
@findex AND, bitwise
|
||||
@item &
|
||||
@ -31956,6 +32041,8 @@ mysql> select 29 & 15;
|
||||
-> 13
|
||||
@end example
|
||||
|
||||
The result is an unsigned 64 bit integer.
|
||||
|
||||
@findex << (left shift)
|
||||
@item <<
|
||||
Shifts a longlong (@code{BIGINT}) number to the left:
|
||||
@ -31964,6 +32051,8 @@ mysql> select 1 << 2;
|
||||
-> 4
|
||||
@end example
|
||||
|
||||
The result is an unsigned 64 bit integer.
|
||||
|
||||
@findex >> (right shift)
|
||||
@item >>
|
||||
Shifts a longlong (@code{BIGINT}) number to the right:
|
||||
@ -31972,6 +32061,8 @@ mysql> select 4 >> 2;
|
||||
-> 1
|
||||
@end example
|
||||
|
||||
The result is an unsigned 64 bit integer.
|
||||
|
||||
@findex ~
|
||||
@item ~
|
||||
Invert all bits:
|
||||
@ -31980,6 +32071,8 @@ mysql> select 5 & ~1;
|
||||
-> 4
|
||||
@end example
|
||||
|
||||
The result is an unsigned 64 bit integer.
|
||||
|
||||
@findex BIT_COUNT()
|
||||
@item BIT_COUNT(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
|
||||
to the original state.
|
||||
|
||||
@code{RENAME TABLE} was added in MySQL 3.23.23.
|
||||
|
||||
@node DROP TABLE, CREATE INDEX, RENAME TABLE, Data Definition
|
||||
@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
|
||||
@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
|
||||
repair tables with @code{nan} in float or double columns.
|
||||
@item
|
||||
@ -48377,8 +48476,8 @@ able to use boolean fulltext search}.
|
||||
@code{LOCATE()} and @code{INSTR()} are case sensitive if neither
|
||||
argument is a binary string.
|
||||
@item
|
||||
Changed @code{RND()} initialization so that @code{RND(N)} and @code{RND(N+1)}
|
||||
are more distinct.
|
||||
Changed @code{RAND()} initialization so that @code{RAND(N)} and
|
||||
@code{RAND(N+1)} are more distinct.
|
||||
@item
|
||||
Fixed core dump bug in @code{UPDATE ... ORDER BY}.
|
||||
@item
|
||||
@ -48603,7 +48702,7 @@ not yet 100% confident in this code.
|
||||
@appendixsubsec Changes in release 3.23.47
|
||||
@itemize @bullet
|
||||
@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}
|
||||
@item
|
||||
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
|
||||
@code{libmysqlclient_r} now.
|
||||
@item
|
||||
Added atomic @code{RENAME} command.
|
||||
Added atomic @code{RENAME TABLE} command.
|
||||
@item
|
||||
Don't count entries with @code{NULL} in @code{COUNT(DISTINCT ...)}.
|
||||
@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",
|
||||
#define ER_DUP_ARGUMENT 225
|
||||
"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
|
||||
, , [
|
||||
test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
|
||||
rm -f $AVAILABLE_LANGUAGES_ERRORS_RULES
|
||||
])
|
||||
|
||||
rm -f $AVAILABLE_LANGUAGES_ERRORS_RULES
|
||||
echo
|
||||
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"
|
||||
@ -2288,6 +2288,6 @@ echo
|
||||
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
|
||||
# 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
|
||||
|
@ -35,10 +35,10 @@ struct my_option
|
||||
enum get_opt_var_type var_type;
|
||||
enum get_opt_arg_type arg_type;
|
||||
int id; /* unique id or short option */
|
||||
long long def_value; /* Default value */
|
||||
long long min_value; /* Min allowed value */
|
||||
long long max_value; /* Max allowed value */
|
||||
long long sub_size; /* Subtract this from given value */
|
||||
longlong def_value; /* Default value */
|
||||
longlong min_value; /* Min allowed value */
|
||||
longlong max_value; /* Max allowed value */
|
||||
longlong sub_size; /* Subtract this from given value */
|
||||
long block_size; /* Value should be a mult. of this */
|
||||
int app_type; /* To be used by an application */
|
||||
my_bool changeable_var; /* If true, the option is a variable */
|
||||
|
@ -51,15 +51,16 @@
|
||||
#endif
|
||||
#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
|
||||
of a condition. This serves two purposes - newer versions of gcc will be
|
||||
able to optimize for branch predication, which could yield siginficant
|
||||
performance gains in frequently executed sections of the code, and the
|
||||
other reason to use them is for documentation
|
||||
/*
|
||||
The macros below are borrowed from include/linux/compiler.h in the
|
||||
Linux kernel. Use them to indicate the likelyhood of the truthfulness
|
||||
of a condition. This serves two purposes - newer versions of gcc will be
|
||||
able to optimize for branch predication, which could yield siginficant
|
||||
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)
|
||||
#endif
|
||||
|
||||
|
@ -242,4 +242,5 @@
|
||||
#define ER_CANT_UPDATE_WITH_READLOCK 1223
|
||||
#define ER_MIXING_NOT_ALLOWED 1224
|
||||
#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);
|
||||
CONVERT('-1',UNSIGNED)
|
||||
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
|
||||
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
|
||||
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 ;
|
||||
0x41 0x41+0 0x41 | 0x7fffffffffffffff | 0 0xffffffffffffffff | 0
|
||||
A 65 9223372036854775807 -1
|
||||
A 65 9223372036854775807 18446744073709551615
|
||||
select 0x31+1,concat(0x31)+1,-0xf;
|
||||
0x31+1 concat(0x31)+1 -0xf
|
||||
50 2 -15
|
||||
|
@ -33,3 +33,7 @@ drop table t1;
|
||||
select CAST(1-2 AS UNSIGNED);
|
||||
select CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER);
|
||||
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
|
||||
{
|
||||
public:
|
||||
Item_int_func() :Item_func() {}
|
||||
Item_int_func(Item *a) :Item_func(a) {}
|
||||
Item_int_func(Item *a,Item *b) :Item_func(a,b) {}
|
||||
Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) {}
|
||||
Item_int_func(List<Item> &list) :Item_func(list) {}
|
||||
Item_int_func() :Item_func() { max_length=21; }
|
||||
Item_int_func(Item *a) :Item_func(a) { max_length=21; }
|
||||
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) { max_length=21; }
|
||||
Item_int_func(List<Item> &list) :Item_func(list) { max_length=21; }
|
||||
double val() { return (double) val_int(); }
|
||||
String *val_str(String*str);
|
||||
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)
|
||||
{
|
||||
if (!t_arg) return result_field;
|
||||
@ -203,7 +203,7 @@ public:
|
||||
double val() { return args[0]->val(); }
|
||||
longlong val_int() { return args[0]->val_int(); }
|
||||
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
|
||||
@ -213,7 +213,7 @@ public:
|
||||
double val() { return args[0]->val(); }
|
||||
longlong val_int() { return args[0]->val_int(); }
|
||||
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) {}
|
||||
longlong val_int();
|
||||
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
|
||||
@ -620,7 +619,7 @@ public:
|
||||
Item_func_bit_or(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||
longlong val_int();
|
||||
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
|
||||
@ -629,7 +628,7 @@ public:
|
||||
Item_func_bit_and(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||
longlong val_int();
|
||||
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
|
||||
@ -638,7 +637,7 @@ public:
|
||||
Item_func_bit_count(Item *a) :Item_int_func(a) {}
|
||||
longlong val_int();
|
||||
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
|
||||
@ -647,7 +646,7 @@ public:
|
||||
Item_func_shift_left(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||
longlong val_int();
|
||||
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
|
||||
@ -656,7 +655,6 @@ public:
|
||||
Item_func_shift_right(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||
longlong val_int();
|
||||
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
|
||||
@ -665,7 +663,7 @@ public:
|
||||
Item_func_bit_neg(Item *a) :Item_int_func(a) {}
|
||||
longlong val_int();
|
||||
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
|
||||
@ -674,7 +672,7 @@ public:
|
||||
Item_func_set_last_insert_id(Item *a) :Item_int_func(a) {}
|
||||
longlong val_int();
|
||||
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
|
||||
@ -686,7 +684,7 @@ class Item_func_benchmark :public Item_int_func
|
||||
{}
|
||||
longlong val_int();
|
||||
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) {}
|
||||
longlong val_int();
|
||||
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
|
||||
@ -828,7 +826,7 @@ class Item_func_release_lock :public Item_int_func
|
||||
Item_func_release_lock(Item *a) :Item_int_func(a) {}
|
||||
longlong val_int();
|
||||
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 */
|
||||
@ -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) {}
|
||||
longlong val_int();
|
||||
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)
|
||||
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
|
||||
cache */
|
||||
|
||||
/*
|
||||
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
|
||||
cache
|
||||
*/
|
||||
if (!(table= (TABLE*) my_malloc(sizeof(*table)+key_length,
|
||||
MYF(MY_WME | MY_ZEROFILL))))
|
||||
DBUG_RETURN(-1);
|
||||
|
49
sql/log.cc
49
sql/log.cc
@ -370,6 +370,7 @@ err:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int MYSQL_LOG::reset_logs(THD* thd)
|
||||
{
|
||||
LOG_INFO linfo;
|
||||
@ -403,6 +404,7 @@ err:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
|
||||
{
|
||||
// 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(rli->slave_running == 1);
|
||||
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 ==
|
||||
strlen(rli->relay_log_name) + 1);
|
||||
|
||||
int tmp_fd;
|
||||
|
||||
|
||||
char* fname, *io_buf;
|
||||
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;
|
||||
pthread_mutex_lock(&LOCK_index);
|
||||
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 (;;)
|
||||
{
|
||||
int bytes_read;
|
||||
bytes_read = my_read(index_file, io_buf, IO_SIZE, MYF(0));
|
||||
if (bytes_read < 0) // error
|
||||
bytes_read = my_read(index_file, (byte*) io_buf, IO_SIZE, MYF(0));
|
||||
if (bytes_read < 0) // error
|
||||
{
|
||||
error=1;
|
||||
goto err;
|
||||
}
|
||||
if (!bytes_read)
|
||||
break; // end of file
|
||||
break; // end of file
|
||||
// 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;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
if (tmp_fd)
|
||||
my_close(tmp_fd, MYF(MY_WME));
|
||||
@ -476,18 +479,20 @@ err:
|
||||
strnmov(rli->relay_log_name,rli->linfo.log_file_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:
|
||||
pthread_mutex_unlock(&LOCK_index);
|
||||
my_free(fname, MYF(MY_WME));
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
char fname[FN_REFLEN];
|
||||
char *p;
|
||||
@ -498,6 +503,10 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
|
||||
LINT_INIT(purge_offset);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
// be safe
|
||||
/*
|
||||
If we get killed -9 here, the sysadmin would have to edit
|
||||
the log index file after restart - otherwise, this should be safe
|
||||
*/
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
if (ftruncate(index_file,0))
|
||||
{
|
||||
@ -737,14 +747,14 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
|
||||
pthread_mutex_lock(&LOCK_log);
|
||||
do
|
||||
{
|
||||
if (my_b_append(&log_file,buf,len))
|
||||
if (my_b_append(&log_file,(byte*) buf,len))
|
||||
{
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
@ -755,6 +765,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
|
||||
const char *format,...)
|
||||
{
|
||||
|
@ -26,17 +26,19 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
inline int my_b_safe_write(IO_CACHE* file, const char* buf,
|
||||
int len)
|
||||
inline int my_b_safe_write(IO_CACHE* file, const byte *buf,
|
||||
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
|
||||
// several layers of ternary operators that evaluated comma(,) operator
|
||||
// expressions inside - I do have a test case if somebody wants it
|
||||
/*
|
||||
Sasha: We are not writing this with the ? operator to avoid hitting
|
||||
a possible compiler bug. At least gcc 2.95 cannot deal with
|
||||
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)
|
||||
return my_b_append(file,buf,len);
|
||||
return my_b_write(file,buf,len);
|
||||
}
|
||||
return my_b_append(file, buf,len);
|
||||
return my_b_write(file, buf,len);
|
||||
}
|
||||
|
||||
#ifdef MYSQL_CLIENT
|
||||
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('\'');
|
||||
}
|
||||
|
||||
|
||||
static inline char* slave_load_file_stem(char*buf, uint file_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();
|
||||
net_store_data(packet, event_type, strlen(event_type));
|
||||
net_store_data(packet, server_id);
|
||||
net_store_data(packet, log_pos);
|
||||
net_store_data(packet, (longlong) log_pos);
|
||||
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
|
||||
@ -1218,31 +1221,30 @@ void Load_log_event::set_fields(List<Item> &fields)
|
||||
{
|
||||
uint i;
|
||||
const char* field = this->fields;
|
||||
for(i = 0; i < num_fields; i++)
|
||||
{
|
||||
fields.push_back(new Item_field(db, table_name, field));
|
||||
field += field_lens[i] + 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_fields; i++)
|
||||
{
|
||||
fields.push_back(new Item_field(db, table_name, field));
|
||||
field += field_lens[i] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Slave_log_event::Slave_log_event(THD* thd_arg,
|
||||
struct st_relay_log_info* rli):
|
||||
Log_event(thd_arg),mem_pool(0),master_host(0)
|
||||
{
|
||||
if(!rli->inited)
|
||||
if (!rli->inited)
|
||||
return;
|
||||
|
||||
MASTER_INFO* mi = rli->mi;
|
||||
// TODO: re-write this better without holding both
|
||||
// locks at the same time
|
||||
// TODO: re-write this better without holding both locks at the same time
|
||||
pthread_mutex_lock(&mi->data_lock);
|
||||
pthread_mutex_lock(&rli->data_lock);
|
||||
master_host_len = strlen(mi->host);
|
||||
master_log_len = strlen(rli->master_log_name);
|
||||
// on OOM, just do not initialize the structure and print the error
|
||||
if((mem_pool = (char*)my_malloc(get_data_size() + 1,
|
||||
MYF(MY_WME))))
|
||||
if ((mem_pool = (char*)my_malloc(get_data_size() + 1,
|
||||
MYF(MY_WME))))
|
||||
{
|
||||
master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
|
||||
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);
|
||||
fputc('\n', file);
|
||||
fprintf(file, "Slave: master_host='%s' master_port=%d \
|
||||
master_log=%s master_pos=%s\n", master_host, master_port, master_log,
|
||||
llstr(master_pos, llbuff));
|
||||
master_log=%s master_pos=%s\n",
|
||||
master_host, master_port, master_log, llstr(master_pos, llbuff));
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1753,11 +1755,13 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli)
|
||||
close_temporary_tables(thd);
|
||||
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
|
||||
// if we updated it, we will have incorrect master coordinates and this
|
||||
// could give false triggers in MASTER_POS_WAIT() that we have reached
|
||||
// the targed position when in fact we have not
|
||||
/*
|
||||
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
|
||||
if we updated it, we will have incorrect master coordinates and this
|
||||
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);
|
||||
flush_relay_log_info(rli);
|
||||
return 0;
|
||||
|
@ -214,7 +214,7 @@ public:
|
||||
time_t when;
|
||||
ulong exec_time;
|
||||
uint32 server_id;
|
||||
uint32 log_pos;
|
||||
my_off_t log_pos;
|
||||
uint16 flags;
|
||||
int cached_event_len;
|
||||
char* temp_buf;
|
||||
@ -351,12 +351,12 @@ protected:
|
||||
char* mem_pool;
|
||||
void init_from_mem_pool(int data_size);
|
||||
public:
|
||||
my_off_t master_pos;
|
||||
char* master_host;
|
||||
int master_host_len;
|
||||
uint16 master_port;
|
||||
char* master_log;
|
||||
int master_host_len;
|
||||
int master_log_len;
|
||||
ulonglong master_pos;
|
||||
uint16 master_port;
|
||||
|
||||
#ifndef MYSQL_CLIENT
|
||||
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;
|
||||
}
|
||||
@ -897,7 +897,7 @@ mc_mysql_close(MYSQL *mysql)
|
||||
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_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;
|
||||
}
|
||||
|
||||
my_ulonglong mc_mysql_num_rows(MYSQL_RES *res)
|
||||
my_ulonglong mc_mysql_num_rows(MYSQL_RES *res)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
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;
|
||||
DBUG_ENTER("mysql_select_db");
|
||||
|
@ -1950,8 +1950,7 @@ The server will not act as a slave.");
|
||||
}
|
||||
if (!opt_noacl)
|
||||
(void) grant_init();
|
||||
if (max_user_connections || mqh_used)
|
||||
init_max_user_conn();
|
||||
init_max_user_conn();
|
||||
|
||||
#ifdef HAVE_DLOPEN
|
||||
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)
|
||||
{
|
||||
uint32 log_pos = mi->pos;
|
||||
uint32 log_pos = (uint32) mi->pos;
|
||||
uint32 target_server_id = mi->server_id;
|
||||
|
||||
for (;;)
|
||||
@ -799,8 +799,7 @@ int load_master_data(THD* thd)
|
||||
{
|
||||
strmake(active_mi->master_log_name, row[0],
|
||||
sizeof(active_mi->master_log_name));
|
||||
// atoi() is ok, since offset is <= 1GB
|
||||
active_mi->master_log_pos = atoi(row[1]);
|
||||
active_mi->master_log_pos = strtoull(row[1], (char**) 0, 10);
|
||||
if (active_mi->master_log_pos < 4)
|
||||
active_mi->master_log_pos = 4; // don't hit the magic number
|
||||
active_mi->rli.pending = 0;
|
||||
|
@ -236,3 +236,4 @@
|
||||
"Can't execute the query because you have a conflicting read lock",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Het combineren van transactionele en niet-transactionele tabellen is uitgeschakeld.",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Transaktsioone toetavate ning mittetoetavate tabelite kooskasutamine ei ole lubatud",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"Option '%s' used twice in statement",
|
||||
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
|
||||
|
@ -230,3 +230,4 @@
|
||||
"Невозможно выполнить запрос из-за конфликтной блокировки чтения",
|
||||
"Одновременное использование transactional и non-transactional таблиц отключено",
|
||||
"Опция '%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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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",
|
||||
"Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat",
|
||||
"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",
|
||||
"Mixing of transactional and non-transactional tables is disabled",
|
||||
"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);
|
||||
rli->pending=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) ||
|
||||
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))
|
||||
goto err;
|
||||
rli->master_log_pos = 0; // uninitialized
|
||||
rli->master_log_pos = 0; // uninitialized
|
||||
rli->info_fd = info_fd;
|
||||
}
|
||||
else // file exists
|
||||
@ -1049,6 +1049,7 @@ err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int init_master_info(MASTER_INFO* mi, const char* master_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;
|
||||
mi->rli.mi = mi;
|
||||
mi->ignore_stop_event=0;
|
||||
int fd,length,error;
|
||||
int fd,error;
|
||||
MY_STAT stat_area;
|
||||
char fname[FN_REFLEN+128];
|
||||
const char *msg;
|
||||
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);
|
||||
fd = mi->fd;
|
||||
@ -1089,7 +1092,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
|
||||
return 1;
|
||||
}
|
||||
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;
|
||||
|
||||
if (master_host)
|
||||
@ -1119,20 +1122,18 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
|
||||
|
||||
mi->fd = fd;
|
||||
if (init_strvar_from_file(mi->master_log_name,
|
||||
sizeof(mi->master_log_name), &mi->file,
|
||||
(char*)"") ||
|
||||
init_intvar_from_file((int*)&mi->master_log_pos, &mi->file, 4)
|
||||
||
|
||||
init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
|
||||
master_host) ||
|
||||
init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
|
||||
master_user) ||
|
||||
init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file,
|
||||
master_password) ||
|
||||
init_intvar_from_file((int*)&mi->port, &mi->file, master_port) ||
|
||||
init_intvar_from_file((int*)&mi->connect_retry, &mi->file,
|
||||
master_connect_retry)
|
||||
)
|
||||
sizeof(mi->master_log_name), &mi->file,
|
||||
(char*)"") ||
|
||||
init_intvar_from_file((int*)&mi->master_log_pos, &mi->file, 4) ||
|
||||
init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
|
||||
master_host) ||
|
||||
init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
|
||||
master_user) ||
|
||||
init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file,
|
||||
master_password) ||
|
||||
init_intvar_from_file((int*)&mi->port, &mi->file, master_port) ||
|
||||
init_intvar_from_file((int*)&mi->connect_retry, &mi->file,
|
||||
master_connect_retry))
|
||||
{
|
||||
msg="Error reading master configuration";
|
||||
goto err;
|
||||
@ -1140,8 +1141,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
|
||||
}
|
||||
|
||||
mi->inited = 1;
|
||||
// now change the cache from READ to WRITE - must do this
|
||||
// before flush_master_info
|
||||
// now change cache READ -> WRITE - must do this before flush_master_info
|
||||
reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1);
|
||||
error=test(flush_master_info(mi));
|
||||
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, mi->rli.last_slave_error);
|
||||
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->data_lock);
|
||||
|
||||
@ -1408,7 +1408,8 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi)
|
||||
int len;
|
||||
int binlog_flags = 0; // for now
|
||||
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);
|
||||
int4store(buf + 6, server_id);
|
||||
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)
|
||||
{
|
||||
const char *error_msg;
|
||||
DBUG_ASSERT(rli->sql_thd==thd);
|
||||
Log_event * ev = next_event(rli);
|
||||
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)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
slave_begin:
|
||||
slave_begin:
|
||||
#endif
|
||||
THD *thd; // needs to be first for thread_stack
|
||||
MYSQL *mysql = NULL ;
|
||||
@ -1604,12 +1604,12 @@ pthread_handler_decl(handle_slave_io,arg)
|
||||
|
||||
pthread_detach_this_thread();
|
||||
if (init_slave_thread(thd, SLAVE_THD_IO))
|
||||
{
|
||||
pthread_cond_broadcast(&mi->start_cond);
|
||||
pthread_mutex_unlock(&mi->run_lock);
|
||||
sql_print_error("Failed during slave I/O thread initialization");
|
||||
goto err;
|
||||
}
|
||||
{
|
||||
pthread_cond_broadcast(&mi->start_cond);
|
||||
pthread_mutex_unlock(&mi->run_lock);
|
||||
sql_print_error("Failed during slave I/O thread initialization");
|
||||
goto err;
|
||||
}
|
||||
mi->io_thd = thd;
|
||||
thd->thread_stack = (char*)&thd; // remember where our stack is
|
||||
threads.append(thd);
|
||||
@ -1633,11 +1633,11 @@ pthread_handler_decl(handle_slave_io,arg)
|
||||
#endif
|
||||
// we can get killed during safe_connect
|
||||
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,
|
||||
mi->host, mi->port,
|
||||
IO_RPL_LOG_NAME,
|
||||
llstr(mi->master_log_pos,llbuff));
|
||||
mi->host, mi->port,
|
||||
IO_RPL_LOG_NAME,
|
||||
llstr(mi->master_log_pos,llbuff));
|
||||
else
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while connecting to master");
|
||||
@ -1649,14 +1649,14 @@ connected:
|
||||
thd->slave_net = &mysql->net;
|
||||
thd->proc_info = "Checking master version";
|
||||
if (check_master_version(mysql, mi))
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
if (!mi->old_format)
|
||||
{
|
||||
// register ourselves with the master
|
||||
// if fails, this is not fatal - we just print the error message and go
|
||||
// on with life
|
||||
/*
|
||||
Register ourselves with the master.
|
||||
If fails, this is not fatal - we just print the error message and go
|
||||
on with life.
|
||||
*/
|
||||
thd->proc_info = "Registering slave on master";
|
||||
if (register_slave_on_master(mysql) || update_slave_list(mysql))
|
||||
goto err;
|
||||
@ -1664,122 +1664,124 @@ connected:
|
||||
|
||||
while (!slave_killed(thd,mi))
|
||||
{
|
||||
thd->proc_info = "Requesting binlog dump";
|
||||
if (request_dump(mysql, mi))
|
||||
{
|
||||
sql_print_error("Failed on request_dump()");
|
||||
if(slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while requesting master \
|
||||
thd->proc_info = "Requesting binlog dump";
|
||||
if (request_dump(mysql, mi))
|
||||
{
|
||||
sql_print_error("Failed on request_dump()");
|
||||
if(slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while requesting master \
|
||||
dump");
|
||||
goto err;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
thd->proc_info = "Waiiting to reconnect after a failed dump request";
|
||||
mc_end_server(mysql);
|
||||
// first time retry immediately, assuming that we can recover
|
||||
// right away - if first time fails, sleep between re-tries
|
||||
// hopefuly the admin can fix the problem sometime
|
||||
if (retried_once)
|
||||
safe_sleep(thd, mi, mi->connect_retry);
|
||||
else
|
||||
retried_once = 1;
|
||||
thd->proc_info = "Waiiting to reconnect after a failed dump request";
|
||||
mc_end_server(mysql);
|
||||
/*
|
||||
First time retry immediately, assuming that we can recover
|
||||
right away - if first time fails, sleep between re-tries
|
||||
hopefuly the admin can fix the problem sometime
|
||||
*/
|
||||
if (retried_once)
|
||||
safe_sleep(thd, mi, mi->connect_retry);
|
||||
else
|
||||
retried_once = 1;
|
||||
|
||||
if (slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while retrying master \
|
||||
if (slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while retrying master \
|
||||
dump");
|
||||
goto err;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
thd->proc_info = "Reconnecting after a failed dump request";
|
||||
sql_print_error("Slave I/O thread: failed dump request, \
|
||||
thd->proc_info = "Reconnecting after a 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,
|
||||
llstr(mi->master_log_pos,llbuff));
|
||||
if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed during or \
|
||||
llstr(mi->master_log_pos,llbuff));
|
||||
if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed during or \
|
||||
after reconnect");
|
||||
goto err;
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
goto connected;
|
||||
}
|
||||
goto connected;
|
||||
}
|
||||
|
||||
while (!slave_killed(thd,mi))
|
||||
{
|
||||
thd->proc_info = "Reading master update";
|
||||
ulong event_len = read_event(mysql, mi);
|
||||
if (slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while reading event");
|
||||
goto err;
|
||||
}
|
||||
while (!slave_killed(thd,mi))
|
||||
{
|
||||
thd->proc_info = "Reading master update";
|
||||
ulong event_len = read_event(mysql, mi);
|
||||
if (slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while reading event");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (event_len == packet_error)
|
||||
{
|
||||
if (mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE)
|
||||
{
|
||||
sql_print_error("Log entry on master is longer than \
|
||||
max_allowed_packet on slave. Slave thread will be aborted. If the entry is \
|
||||
really supposed to be that long, restart the server with a higher value of \
|
||||
max_allowed_packet. The current value is %ld", max_allowed_packet);
|
||||
goto err;
|
||||
}
|
||||
if (event_len == packet_error)
|
||||
{
|
||||
if (mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE)
|
||||
{
|
||||
sql_print_error("Log entry on master is longer than \
|
||||
max_allowed_packet (%ld) on slave. Slave thread will be aborted. If the entry \
|
||||
is correct, restart the server with a higher value of max_allowed_packet",
|
||||
max_allowed_packet);
|
||||
goto err;
|
||||
}
|
||||
|
||||
thd->proc_info = "Waiting to reconnect after a failed read";
|
||||
mc_end_server(mysql);
|
||||
if (retried_once) // punish repeat offender with sleep
|
||||
safe_sleep(thd,mi,mi->connect_retry);
|
||||
else
|
||||
retried_once = 1;
|
||||
thd->proc_info = "Waiting to reconnect after a failed read";
|
||||
mc_end_server(mysql);
|
||||
if (retried_once) // punish repeat offender with sleep
|
||||
safe_sleep(thd,mi,mi->connect_retry);
|
||||
else
|
||||
retried_once = 1;
|
||||
|
||||
if (slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while waiting to \
|
||||
if (slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while waiting to \
|
||||
reconnect after a failed read");
|
||||
goto err;
|
||||
}
|
||||
thd->proc_info = "Reconnecting after a failed read";
|
||||
sql_print_error("Slave I/O thread: Failed reading log event, \
|
||||
goto err;
|
||||
}
|
||||
thd->proc_info = "Reconnecting after a failed read";
|
||||
sql_print_error("Slave I/O thread: Failed reading log event, \
|
||||
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
|
||||
llstr(mi->master_log_pos, llbuff));
|
||||
if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed during or after a \
|
||||
llstr(mi->master_log_pos, llbuff));
|
||||
if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed during or after a \
|
||||
reconnect done to recover from failed read");
|
||||
goto err;
|
||||
}
|
||||
goto connected;
|
||||
} // if(event_len == packet_error)
|
||||
goto err;
|
||||
}
|
||||
goto connected;
|
||||
} // if(event_len == packet_error)
|
||||
|
||||
thd->proc_info = "Queueing event from master";
|
||||
if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
|
||||
(uint)event_len))
|
||||
{
|
||||
sql_print_error("Slave I/O thread could not queue event \
|
||||
thd->proc_info = "Queueing event from master";
|
||||
if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
|
||||
event_len))
|
||||
{
|
||||
sql_print_error("Slave I/O thread could not queue event \
|
||||
from master");
|
||||
goto err;
|
||||
}
|
||||
// TODO: check debugging abort code
|
||||
goto err;
|
||||
}
|
||||
// TODO: check debugging abort code
|
||||
#ifndef DBUG_OFF
|
||||
if (abort_slave_event_count && !--events_till_abort)
|
||||
{
|
||||
sql_print_error("Slave I/O thread: debugging abort");
|
||||
goto err;
|
||||
}
|
||||
if (abort_slave_event_count && !--events_till_abort)
|
||||
{
|
||||
sql_print_error("Slave I/O thread: debugging abort");
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
} // while(!slave_killed(thd,mi)) - read/exec loop
|
||||
} // while(!slave_killed(thd,mi)) - read/exec loop
|
||||
} // while(!slave_killed(thd,mi)) - slave loop
|
||||
|
||||
// error = 0;
|
||||
err:
|
||||
err:
|
||||
// print the current replication position
|
||||
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));
|
||||
thd->query = thd->db = 0; // extra safety
|
||||
if(mysql)
|
||||
mc_mysql_close(mysql);
|
||||
mc_mysql_close(mysql);
|
||||
thd->proc_info = "Waiting for slave mutex on exit";
|
||||
pthread_mutex_lock(&mi->run_lock);
|
||||
mi->slave_running = 0;
|
||||
@ -1803,12 +1805,13 @@ from master");
|
||||
DBUG_RETURN(0); // Can't return anything here
|
||||
}
|
||||
|
||||
|
||||
/* slave SQL logic thread */
|
||||
|
||||
pthread_handler_decl(handle_slave_sql,arg)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
slave_begin:
|
||||
slave_begin:
|
||||
#endif
|
||||
THD *thd; /* needs to be first for thread_stack */
|
||||
MYSQL *mysql = NULL ;
|
||||
@ -1832,14 +1835,16 @@ pthread_handler_decl(handle_slave_sql,arg)
|
||||
|
||||
pthread_detach_this_thread();
|
||||
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
|
||||
pthread_cond_broadcast(&rli->start_cond);
|
||||
pthread_mutex_unlock(&rli->run_lock);
|
||||
sql_print_error("Failed during slave thread initialization");
|
||||
goto err;
|
||||
}
|
||||
{
|
||||
/*
|
||||
TODO: this is currently broken - slave start and change master
|
||||
will be stuck if we fail here
|
||||
*/
|
||||
pthread_cond_broadcast(&rli->start_cond);
|
||||
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->temporary_tables = rli->save_temporary_tables; // restore temp tables
|
||||
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))
|
||||
sql_print_error("\
|
||||
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",
|
||||
RPL_LOG_NAME, llstr(rli->master_log_pos, llbuff));
|
||||
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
|
||||
rli->slave_running = 0;
|
||||
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;
|
||||
thd->temporary_tables = 0; // remove tempation from destructor to close them
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
// We assume we already locked mi->data_lock
|
||||
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_pos = rev->pos;
|
||||
#ifndef DBUG_OFF
|
||||
/* if we do not do this, we will be getting the first
|
||||
rotate event forever, so
|
||||
we need to not disconnect after one
|
||||
*/
|
||||
if (disconnect_slave_event_count)
|
||||
events_till_disconnect++;
|
||||
/*
|
||||
If we do not do this, we will be getting the first
|
||||
rotate event forever, so we need to not disconnect after one.
|
||||
*/
|
||||
if (disconnect_slave_event_count)
|
||||
events_till_disconnect++;
|
||||
#endif
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TODO: verify the issue with stop events, see if we need them at all
|
||||
// in the relay log
|
||||
// TODO: test this code before release - it has to be tested on a separte
|
||||
// setup with 3.23 master
|
||||
static int queue_old_event(MASTER_INFO* mi, const char* buf,
|
||||
uint event_len)
|
||||
/*
|
||||
TODO: verify the issue with stop events, see if we need them at all
|
||||
in the relay log
|
||||
TODO: test this code before release - it has to be tested on a separte
|
||||
setup with 3.23 master
|
||||
*/
|
||||
|
||||
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 processed_stop_event = 0;
|
||||
Log_event* ev = Log_event::read_log_event(buf,event_len, &errmsg,
|
||||
1/*old format*/);
|
||||
Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
|
||||
1 /*old format*/ );
|
||||
if (unlikely(!ev))
|
||||
{
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
pthread_mutex_lock(&mi->data_lock);
|
||||
ev->log_pos = mi->master_log_pos;
|
||||
switch (ev->get_type_code())
|
||||
{
|
||||
switch (ev->get_type_code()) {
|
||||
case ROTATE_EVENT:
|
||||
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;
|
||||
}
|
||||
|
||||
// TODO: verify the issue with stop events, see if we need them at all
|
||||
// in the relay log
|
||||
int queue_event(MASTER_INFO* mi,const char* buf,uint event_len)
|
||||
/*
|
||||
TODO: verify the issue with stop events, see if we need them at all
|
||||
in the relay log
|
||||
*/
|
||||
|
||||
int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
|
||||
{
|
||||
int error=0;
|
||||
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);
|
||||
|
||||
// TODO: figure out if other events in addition to Rotate
|
||||
// require special processing
|
||||
switch (buf[EVENT_TYPE_OFFSET])
|
||||
{
|
||||
/*
|
||||
TODO: figure out if other events in addition to Rotate
|
||||
require special processing
|
||||
*/
|
||||
switch (buf[EVENT_TYPE_OFFSET]) {
|
||||
case STOP_EVENT:
|
||||
processed_stop_event=1;
|
||||
break;
|
||||
@ -2048,22 +2063,23 @@ int queue_event(MASTER_INFO* mi,const char* buf,uint event_len)
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
void end_relay_log_info(RELAY_LOG_INFO* rli)
|
||||
{
|
||||
if (!rli->inited)
|
||||
return;
|
||||
if (rli->info_fd >= 0)
|
||||
{
|
||||
end_io_cache(&rli->info_file);
|
||||
(void)my_close(rli->info_fd, MYF(MY_WME));
|
||||
rli->info_fd = -1;
|
||||
}
|
||||
{
|
||||
end_io_cache(&rli->info_file);
|
||||
(void)my_close(rli->info_fd, MYF(MY_WME));
|
||||
rli->info_fd = -1;
|
||||
}
|
||||
if (rli->cur_log_fd >= 0)
|
||||
{
|
||||
end_io_cache(&rli->cache_buf);
|
||||
(void)my_close(rli->cur_log_fd, MYF(MY_WME));
|
||||
rli->cur_log_fd = -1;
|
||||
}
|
||||
{
|
||||
end_io_cache(&rli->cache_buf);
|
||||
(void)my_close(rli->cur_log_fd, MYF(MY_WME));
|
||||
rli->cur_log_fd = -1;
|
||||
}
|
||||
rli->inited = 0;
|
||||
rli->log_pos_current=0;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Try to connect until successful or slave killed or we have retried
|
||||
master_retry_count times
|
||||
*/
|
||||
|
||||
static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
|
||||
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;
|
||||
#endif
|
||||
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,
|
||||
mi->port, 0, 0)))
|
||||
mi->port, 0, 0)))
|
||||
{
|
||||
/* Don't repeat last error */
|
||||
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);
|
||||
}
|
||||
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
|
||||
do not want to have electioin triggered on the first failure to
|
||||
connect
|
||||
/*
|
||||
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
|
||||
do not want to have electioin triggered on the first failure to
|
||||
connect
|
||||
*/
|
||||
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)
|
||||
sql_print_error("Slave: connected to master '%s@%s:%d',\
|
||||
replication resumed in log '%s' at position %s", mi->user,
|
||||
mi->host, mi->port,
|
||||
IO_RPL_LOG_NAME,
|
||||
llstr(mi->master_log_pos,llbuff));
|
||||
mi->host, mi->port,
|
||||
IO_RPL_LOG_NAME,
|
||||
llstr(mi->master_log_pos,llbuff));
|
||||
else
|
||||
{
|
||||
change_rpl_status(RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE);
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Try to connect until successful or slave killed or we have retried
|
||||
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;
|
||||
DBUG_ASSERT(rli->cur_log_fd == -1);
|
||||
if ((rli->cur_log_fd=open_binlog(cur_log,rli->relay_log_name,
|
||||
errmsg))<0)
|
||||
errmsg)) <0)
|
||||
return 0;
|
||||
my_b_seek(cur_log,rli->relay_log_pos);
|
||||
return cur_log;
|
||||
@ -2188,29 +2208,36 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
|
||||
bool was_killed;
|
||||
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
|
||||
// However, we will release it whenever it is worth the hassle,
|
||||
// and in the cases when we go into a pthread_cond_wait() with the
|
||||
// non-data_lock mutex
|
||||
/*
|
||||
For most operations we need to protect rli members with data_lock,
|
||||
so we will hold it for the most of the loop below
|
||||
However, we will release it whenever it is worth the hassle,
|
||||
and in the cases when we go into a pthread_cond_wait() with the
|
||||
non-data_lock mutex
|
||||
*/
|
||||
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
|
||||
// is actively being updated by the I/O thread. We need to be careful
|
||||
// in this case and make sure that we are not looking at a stale log that
|
||||
// has already been rotated. If it has been, we reopen the log
|
||||
// the other case is much simpler - we just have a read only log that
|
||||
// nobody else will be updating.
|
||||
/*
|
||||
We can have two kinds of log reading:
|
||||
hot_log - rli->cur_log points at the IO_CACHE of relay_log, which
|
||||
is actively being updated by the I/O thread. We need to be careful
|
||||
in this case and make sure that we are not looking at a stale log that
|
||||
has already been rotated. If it has been, we reopen the log
|
||||
the other case is much simpler - we just have a read only log that
|
||||
nobody else will be updating.
|
||||
*/
|
||||
bool hot_log;
|
||||
if ((hot_log = (cur_log != &rli->cache_buf)))
|
||||
{
|
||||
DBUG_ASSERT(rli->cur_log_fd == -1); // foreign descriptor
|
||||
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=reopen_relay_log(rli,&errmsg)))
|
||||
@ -2235,29 +2262,37 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
|
||||
DBUG_ASSERT(thd==rli->sql_thd);
|
||||
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
|
||||
// signals us to continue
|
||||
/*
|
||||
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
|
||||
signals us to continue
|
||||
*/
|
||||
if (hot_log)
|
||||
{
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
// re-acquire data lock since we released it earlier
|
||||
pthread_mutex_lock(&rli->data_lock);
|
||||
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
|
||||
{
|
||||
/*
|
||||
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);
|
||||
DBUG_ASSERT(rli->cur_log_fd >= 0);
|
||||
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;
|
||||
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))
|
||||
goto err;
|
||||
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
|
||||
sql_print_error("next log '%s' is not active",
|
||||
rli->linfo.log_file_name);
|
||||
#endif
|
||||
// open_binlog() will check the magic header
|
||||
if ((rli->cur_log_fd=open_binlog(cur_log,rli->linfo.log_file_name,
|
||||
&errmsg))<0)
|
||||
&errmsg)) <0)
|
||||
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;
|
||||
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); \
|
||||
++active_mi_in_use; \
|
||||
pthread_mutex_unlock(&LOCK_active_mi);}
|
||||
@ -62,50 +65,64 @@ struct st_master_info;
|
||||
|
||||
To clean up, call end_relay_log_info()
|
||||
*/
|
||||
|
||||
typedef struct st_relay_log_info
|
||||
{
|
||||
// info_fd - file descriptor of the info file. set only during
|
||||
// initialization or clean up - safe to read anytime
|
||||
// cur_log_fd - file descriptor of the current read relay log, protected by
|
||||
// data_lock
|
||||
/*** The following variables can only be read when protect by data lock ****/
|
||||
/*
|
||||
info_fd - file descriptor of the info file. set only during
|
||||
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;
|
||||
|
||||
// IO_CACHE of the info file - set only during init or end, safe to read
|
||||
// anytime
|
||||
// name of current read relay log
|
||||
char relay_log_name[FN_REFLEN];
|
||||
// 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;
|
||||
|
||||
// name of current read relay log - protected by data_lock
|
||||
char relay_log_name[FN_REFLEN];
|
||||
|
||||
// master log name corresponding to current read position - protected by
|
||||
// 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
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
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
|
||||
// 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;
|
||||
|
||||
// standard lock acquistion order to avoid deadlocks:
|
||||
// run_lock, data_lock, relay_log.LOCK_log,relay_log.LOCK_index
|
||||
/*
|
||||
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;
|
||||
|
||||
// start_cond is broadcast when SQL thread is started
|
||||
// stop_cond - when stopped
|
||||
// data_cond - when data protected by data_lock changes
|
||||
pthread_cond_t start_cond,stop_cond,data_cond;
|
||||
/*
|
||||
start_cond is broadcast when SQL thread is started
|
||||
stop_cond - when stopped
|
||||
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
|
||||
bool inited;
|
||||
@ -113,21 +130,19 @@ typedef struct st_relay_log_info
|
||||
// parent master info structure
|
||||
struct st_master_info *mi;
|
||||
|
||||
// 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;
|
||||
|
||||
/* needed to deal properly with cur_log getting closed and re-opened with
|
||||
a different log under our feet
|
||||
/*
|
||||
Needed to deal properly with cur_log getting closed and re-opened with
|
||||
a different log under our feet
|
||||
*/
|
||||
int cur_log_init_count;
|
||||
|
||||
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;
|
||||
#ifndef DBUG_OFF
|
||||
int events_till_abort;
|
||||
@ -168,13 +183,15 @@ typedef struct st_relay_log_info
|
||||
relay_log_pos += val+pending;
|
||||
pending = 0;
|
||||
if (log_pos)
|
||||
master_log_pos = log_pos+val;
|
||||
master_log_pos = log_pos+ val;
|
||||
pthread_cond_broadcast(&data_cond);
|
||||
if (!skip_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)
|
||||
{
|
||||
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);
|
||||
} 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);
|
||||
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
|
||||
control variables
|
||||
|
||||
@ -214,14 +236,14 @@ Log_event* next_event(RELAY_LOG_INFO* rli);
|
||||
flush_master_info() is required.
|
||||
|
||||
To clean up, call end_master_info()
|
||||
|
||||
*/
|
||||
|
||||
|
||||
typedef struct st_master_info
|
||||
{
|
||||
char master_log_name[FN_REFLEN];
|
||||
|
||||
ulonglong master_log_pos;
|
||||
my_off_t master_log_pos;
|
||||
File fd;
|
||||
IO_CACHE file;
|
||||
|
||||
@ -229,24 +251,22 @@ typedef struct st_master_info
|
||||
char host[HOSTNAME_LENGTH+1];
|
||||
char user[USERNAME_LENGTH+1];
|
||||
char password[HASH_PASSWORD_LENGTH+1];
|
||||
uint port;
|
||||
uint connect_retry;
|
||||
pthread_mutex_t data_lock,run_lock;
|
||||
pthread_cond_t data_cond,start_cond,stop_cond;
|
||||
bool inited;
|
||||
bool old_format; /* master binlog is in 3.23 format */
|
||||
THD *io_thd;
|
||||
RELAY_LOG_INFO rli;
|
||||
uint port;
|
||||
uint connect_retry;
|
||||
#ifndef DBUG_OFF
|
||||
int events_till_abort;
|
||||
#endif
|
||||
bool inited;
|
||||
bool old_format; // master binlog is in 3.23 format
|
||||
volatile bool abort_slave, slave_running;
|
||||
|
||||
bool ignore_stop_event;
|
||||
|
||||
THD* io_thd;
|
||||
|
||||
st_master_info():fd(-1),inited(0),
|
||||
old_format(0),io_thd(0)
|
||||
st_master_info():fd(-1), io_thd(0), inited(0), old_format(0)
|
||||
{
|
||||
host[0] = 0; user[0] = 0; password[0] = 0;
|
||||
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
|
||||
@ -267,7 +287,7 @@ typedef struct st_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
|
||||
{
|
||||
@ -288,10 +308,12 @@ typedef struct st_table_rule_ent
|
||||
/* masks for start/stop operations on io and sql slave threads */
|
||||
#define SLAVE_IO 1
|
||||
#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();
|
||||
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,
|
||||
MASTER_INFO* mi, const char* master_info_fname,
|
||||
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
|
||||
inside the start_lock section, but at the same time we want a
|
||||
pthread_cond_wait() on start_cond,start_lock
|
||||
/*
|
||||
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
|
||||
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,
|
||||
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,
|
||||
MASTER_INFO* mi);
|
||||
|
||||
// If fd is -1, dump to NET
|
||||
int mysql_table_dump(THD* thd, const char* db,
|
||||
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
|
||||
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_binlog_info(THD* thd);
|
||||
|
||||
// See if the query uses any tables that should not be replicated
|
||||
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,
|
||||
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_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
|
||||
extern uint master_port, master_connect_retry, report_port;
|
||||
extern my_string master_user, master_password, master_host,
|
||||
master_info_file, relay_log_info_file, report_user, report_host,
|
||||
report_password;
|
||||
master_info_file, relay_log_info_file, report_user, report_host,
|
||||
report_password;
|
||||
|
||||
extern I_List<i_string> replicate_do_db, replicate_ignore_db;
|
||||
extern I_List<i_string_pair> replicate_rewrite_db;
|
||||
extern I_List<THD> threads;
|
||||
|
||||
#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
|
||||
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,
|
||||
const char *ip);
|
||||
|
||||
int acl_init(bool dont_read_acl_tables)
|
||||
int acl_init(bool dont_read_acl_tables)
|
||||
{
|
||||
THD *thd;
|
||||
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;
|
||||
if (table->fields >=23)
|
||||
{
|
||||
/* Table has new MySQL usage limits */
|
||||
char *ptr = get_field(&mem, table, 21);
|
||||
user.questions=atoi(ptr);
|
||||
ptr = get_field(&mem, table, 22);
|
||||
user.updates=atoi(ptr);
|
||||
if (user.questions)
|
||||
mqh_used=true;
|
||||
mqh_used=1;
|
||||
}
|
||||
else
|
||||
user.questions=user.updates=0;
|
||||
#ifndef TO_BE_REMOVED
|
||||
if (table->fields <= 13)
|
||||
{ // 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,
|
||||
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;
|
||||
*priv_user=(char*) user;
|
||||
char *ptr=0;
|
||||
|
||||
*max_questions=0;
|
||||
if (!initialized)
|
||||
return (uint) ~NO_ACCESS; // If no data allow anything /* purecov: tested */
|
||||
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 */
|
||||
user_access=acl_user->access;
|
||||
#endif /* HAVE_OPENSSL */
|
||||
*max=acl_user->questions;
|
||||
*max_questions=acl_user->questions;
|
||||
if (!acl_user->user)
|
||||
*priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
|
||||
break;
|
||||
@ -1221,12 +1229,10 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_OPENSSL */
|
||||
if (table->fields>=23 && thd->lex.mqh)
|
||||
if (table->fields >= 23 && thd->lex.mqh)
|
||||
{
|
||||
char buff[33];
|
||||
int len =int2str((long)thd->lex.mqh,buff,10) - buff;
|
||||
table->field[21]->store(buff,len);
|
||||
mqh_used=true;
|
||||
table->field[21]->store((longlong) thd->lex.mqh);
|
||||
mqh_used=1;
|
||||
}
|
||||
if (old_row_exists)
|
||||
{
|
||||
@ -2181,7 +2187,7 @@ int grant_init (void)
|
||||
delete thd;
|
||||
DBUG_RETURN(0); // Empty table is ok!
|
||||
}
|
||||
grant_option = TRUE;
|
||||
grant_option= TRUE;
|
||||
t_table->file->index_end();
|
||||
|
||||
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 */
|
||||
|
||||
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;
|
||||
table->version=0L; /* Free when thread is ready */
|
||||
if (!(in_use=table->in_use))
|
||||
{
|
||||
DBUG_PRINT("info",("Table was not in use"));
|
||||
relink_unused(table);
|
||||
}
|
||||
else if (in_use != thd)
|
||||
{
|
||||
in_use->some_tables_deleted=1;
|
||||
|
@ -3088,6 +3088,7 @@ my_bool Query_cache::check_integrity(bool not_locked)
|
||||
result = 1;
|
||||
break;
|
||||
case Query_cache_block::QUERY:
|
||||
{
|
||||
if (in_list(queries_blocks, block, "query"))
|
||||
result = 1;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Query_cache_block::RES_INCOMPLETE:
|
||||
// This type of block can be not lincked yet (in multithread environment)
|
||||
break;
|
||||
|
@ -370,7 +370,7 @@ public:
|
||||
*/
|
||||
ulong slave_proxy_id;
|
||||
NET* slave_net; // network connection from slave -> m.
|
||||
uint32 log_pos;
|
||||
my_off_t log_pos;
|
||||
|
||||
THD();
|
||||
~THD();
|
||||
|
@ -305,6 +305,8 @@ multi_delete::~multi_delete()
|
||||
bool multi_delete::send_data(List<Item> &values)
|
||||
{
|
||||
int secure_counter= -1;
|
||||
DBUG_ENTER("multi_delete::send_data");
|
||||
|
||||
for (table_being_deleted=delete_tables ;
|
||||
table_being_deleted ;
|
||||
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 this is the table we are scanning */
|
||||
table->status|= STATUS_DELETED;
|
||||
if (!(error=table->file->delete_row(table->record[0])))
|
||||
deleted++;
|
||||
else
|
||||
{
|
||||
table->file->print_error(error,MYF(0));
|
||||
return 1;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -334,21 +337,23 @@ bool multi_delete::send_data(List<Item> &values)
|
||||
if (error)
|
||||
{
|
||||
error=-1;
|
||||
return 1;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
void multi_delete::send_error(uint errcode,const char *err)
|
||||
{
|
||||
DBUG_ENTER("multi_delete::send_error");
|
||||
|
||||
/* First send error what ever it is ... */
|
||||
::send_error(&thd->net,errcode,err);
|
||||
|
||||
/* If nothing deleted return */
|
||||
if (!deleted)
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
/* Below can happen when thread is killed early ... */
|
||||
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)
|
||||
ha_rollback_stmt(thd);
|
||||
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
|
||||
*/
|
||||
|
||||
int multi_delete::do_deletes (bool from_send_error)
|
||||
int multi_delete::do_deletes(bool from_send_error)
|
||||
{
|
||||
int error = 0, counter = 0;
|
||||
|
||||
@ -432,7 +440,7 @@ bool multi_delete::send_eof()
|
||||
thd->proc_info="deleting from reference tables";
|
||||
|
||||
/* 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 */
|
||||
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[]=
|
||||
{ RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV };
|
||||
|
||||
|
||||
int mysql_ha_read(THD *thd, TABLE_LIST *tables,
|
||||
enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr,
|
||||
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.push_front(new Item_field(NULL,NULL,"*"));
|
||||
List_iterator<Item> it(list);
|
||||
uint num_rows;
|
||||
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)
|
||||
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:
|
||||
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:
|
||||
{
|
||||
DBUG_ASSERT(keyname != 0);
|
||||
KEY *keyinfo=table->key_info+keyno;
|
||||
KEY_PART_INFO *key_part=keyinfo->key_part;
|
||||
uint key_len;
|
||||
byte *key;
|
||||
if (key_expr->elements > keyinfo->key_parts)
|
||||
{
|
||||
my_printf_error(ER_TOO_MANY_KEY_PARTS,ER(ER_TOO_MANY_KEY_PARTS),
|
||||
MYF(0),keyinfo->key_parts);
|
||||
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;
|
||||
DBUG_ASSERT(keyname != 0);
|
||||
KEY *keyinfo=table->key_info+keyno;
|
||||
KEY_PART_INFO *key_part=keyinfo->key_part;
|
||||
uint key_len;
|
||||
byte *key;
|
||||
if (key_expr->elements > keyinfo->key_parts)
|
||||
{
|
||||
my_printf_error(ER_TOO_MANY_KEY_PARTS,ER(ER_TOO_MANY_KEY_PARTS),
|
||||
MYF(0),keyinfo->key_parts);
|
||||
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)
|
||||
|
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
|
||||
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);
|
||||
#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 bool check_db_used(THD *thd,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 {
|
||||
char *user;
|
||||
uint len, connections, questions, max;
|
||||
uint len, connections, questions, max_questions;
|
||||
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
|
||||
** returns 0 if OK.
|
||||
*/
|
||||
|
||||
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
|
||||
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,
|
||||
const char *passwd, const char *db, bool check_count)
|
||||
{
|
||||
NET *net= &thd->net;
|
||||
uint max=0;
|
||||
uint max_questions=0;
|
||||
thd->db=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,
|
||||
protocol_version == 9 ||
|
||||
!(thd->client_capabilities &
|
||||
CLIENT_LONG_PASSWORD),&max);
|
||||
CLIENT_LONG_PASSWORD),&max_questions);
|
||||
DBUG_PRINT("info",
|
||||
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (mqh_used && max && check_mqh(thd,user,thd->host,max))
|
||||
return -1;
|
||||
mysql_log.write(thd,command,
|
||||
(thd->priv_user == thd->user ?
|
||||
(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,
|
||||
db ? db : (char*) "");
|
||||
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 &&
|
||||
check_for_max_user_connections(user, thd->host, max))
|
||||
check_for_max_user_connections(user, thd->host, max_questions))
|
||||
return -1;
|
||||
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
|
||||
** if mysql server is started with corresponding
|
||||
** variable that is greater then 0
|
||||
Check for maximum allowable user connections, if the mysqld server is
|
||||
started with corresponding 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) 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,
|
||||
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;
|
||||
uint temp_len;
|
||||
char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
|
||||
struct user_conn *uc;
|
||||
if (!user)
|
||||
user="";
|
||||
if (!host)
|
||||
host="";
|
||||
DBUG_ENTER("check_for_max_user_connections");
|
||||
DBUG_ASSERT(user != 0);
|
||||
DBUG_ASSERT(host != 0);
|
||||
DBUG_PRINT("enter",("user: '%s' host: '%s'", 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->connections = 1;
|
||||
uc->questions=0;
|
||||
uc->max=max;
|
||||
uc->max_questions=max_questions;
|
||||
uc->intime=current_thd->thr_create_time;
|
||||
if (hash_insert(&hash_user_connections, (byte*) uc))
|
||||
{
|
||||
@ -397,9 +331,82 @@ void free_max_user_conn(void)
|
||||
hash_free(&hash_user_connections);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** check connnetion and get priviliges
|
||||
** returns 0 on ok, -1 < if error is given > 0 on error.
|
||||
Check if maximum queries per hour limit has been reached
|
||||
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;
|
||||
NET *net= &thd->net;
|
||||
/*
|
||||
** store the connection details
|
||||
*/
|
||||
/* Store the connection details */
|
||||
DBUG_PRINT("info", (("check_connections called by thread %d"),
|
||||
thd->thread_id));
|
||||
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))
|
||||
{
|
||||
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,
|
||||
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);
|
||||
if (!skip_error)
|
||||
return ren_table;
|
||||
DBUG_RETURN(ren_table);
|
||||
}
|
||||
else if (mysql_rename_table(table_type,
|
||||
ren_table->db, ren_table->name,
|
||||
|
@ -763,7 +763,6 @@ int change_master(THD* thd, MASTER_INFO* mi)
|
||||
1 /* wait for start*/,
|
||||
mi,master_info_file,relay_log_info_file,
|
||||
restart_thread_mask);
|
||||
err:
|
||||
unlock_slave_threads(mi);
|
||||
thd->proc_info = 0;
|
||||
if (error)
|
||||
@ -1006,9 +1005,9 @@ int log_loaded_block(IO_CACHE* file)
|
||||
|
||||
/* file->request_pos contains position where we started last read */
|
||||
char* buffer = (char*) file->request_pos;
|
||||
if (!(block_len = file->read_end - buffer))
|
||||
if (!(block_len = (char*) file->read_end - (char*) buffer))
|
||||
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 &&
|
||||
lf_info->last_pos_in_file >= file->pos_in_file)
|
||||
return 0;
|
||||
@ -1030,5 +1029,3 @@ int log_loaded_block(IO_CACHE* file)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -185,7 +185,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
ulong select_options,select_result *result)
|
||||
{
|
||||
TABLE *tmp_table;
|
||||
int error, tmp_error, tmp;
|
||||
int error, tmp_error;
|
||||
bool need_tmp,hidden_group_fields;
|
||||
bool simple_order,simple_group,no_order, skip_sort_order;
|
||||
Item::cond_result cond_value;
|
||||
|
@ -708,7 +708,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
|
||||
|
||||
/* Null flag */
|
||||
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,table->file->index_type(i));
|
||||
/* Comment */
|
||||
|
@ -613,10 +613,12 @@ bool multi_update::send_data(List<Item> &values)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Here I insert into each temporary table
|
||||
values_by_table.push_front(new Item_string(table->file->ref,table->file->ref_length));
|
||||
// Here we insert into each temporary table
|
||||
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);
|
||||
error= write_record(tmp_tables[secure_counter],&(infos[secure_counter]));
|
||||
error= write_record(tmp_tables[secure_counter],
|
||||
&(infos[secure_counter]));
|
||||
if (error)
|
||||
{
|
||||
error=-1;
|
||||
@ -661,7 +663,8 @@ int multi_update::do_updates (bool from_send_error)
|
||||
{
|
||||
int error = 0, counter = 0;
|
||||
|
||||
if (num_updated == 1) return 0;
|
||||
if (num_updated == 1)
|
||||
return 0;
|
||||
if (from_send_error)
|
||||
{
|
||||
/* Found out table number for 'table_being_updated' */
|
||||
@ -690,7 +693,7 @@ int multi_update::do_updates (bool from_send_error)
|
||||
}
|
||||
List<Item> list;
|
||||
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;
|
||||
while ((field = *ptr++))
|
||||
{
|
||||
@ -709,12 +712,14 @@ int multi_update::do_updates (bool from_send_error)
|
||||
(!thd->killed || from_send_error || not_trans_safe))
|
||||
{
|
||||
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)
|
||||
return error;
|
||||
table->status|= STATUS_UPDATED;
|
||||
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]);
|
||||
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()
|
||||
{
|
||||
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 */
|
||||
int error = do_updates(false); /* do_updates returns 0 if success */
|
||||
|
||||
/* reset used flags */
|
||||
// update_tables->table->no_keyread=0;
|
||||
if (error == -1) error = 0;
|
||||
#ifndef NOT_USED
|
||||
update_tables->table->no_keyread=0;
|
||||
#endif
|
||||
if (error == -1)
|
||||
error = 0;
|
||||
thd->proc_info="end";
|
||||
if (error)
|
||||
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
|
||||
was a non-transaction-safe table involved, since
|
||||
modifications in it cannot be rolled back. */
|
||||
/*
|
||||
Write the SQL statement to the binlog if we updated
|
||||
rows and we succeeded, or also in an error case when there
|
||||
was a non-transaction-safe table involved, since
|
||||
modifications in it cannot be rolled back.
|
||||
*/
|
||||
|
||||
if (updated || not_trans_safe)
|
||||
{
|
||||
mysql_update_log.write(thd,thd->query,thd->query_length);
|
||||
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) &&
|
||||
!not_trans_safe)
|
||||
error=1; /* Log write failed: roll back
|
||||
the SQL statement */
|
||||
error=1; /* Log write failed: roll back the SQL statement */
|
||||
|
||||
/* Commit or rollback the current SQL statement */
|
||||
|
||||
VOID(ha_autocommit_or_rollback(thd,error > 0));
|
||||
}
|
||||
else
|
||||
@ -777,8 +789,8 @@ bool multi_update::send_eof()
|
||||
if (updated)
|
||||
query_cache.invalidate(update_tables);
|
||||
::send_ok(&thd->net,
|
||||
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
|
||||
thd->insert_id_used ? thd->insert_id() : 0L,buff);
|
||||
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
|
||||
thd->insert_id_used ? thd->insert_id() : 0L,buff);
|
||||
}
|
||||
thd->count_cuted_fields=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_attribute opt_attribute_list attribute column_list column_list_id
|
||||
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
|
||||
equal optional_braces opt_key_definition key_usage_list2
|
||||
opt_mi_check_type opt_to mi_check_types normal_join
|
||||
@ -3395,7 +3395,7 @@ grant:
|
||||
lex->mqh=0;
|
||||
}
|
||||
grant_privileges ON opt_table TO_SYM user_list
|
||||
require_clause grant_option mqh_option
|
||||
require_clause grant_options
|
||||
|
||||
grant_privileges:
|
||||
grant_privilege_list {}
|
||||
@ -3582,17 +3582,19 @@ require_clause: /* empty */
|
||||
Lex->ssl_type=SSL_TYPE_X509;
|
||||
}
|
||||
|
||||
grant_option:
|
||||
grant_options:
|
||||
/* empty */ {}
|
||||
| WITH GRANT OPTION { Lex->grant |= GRANT_ACL;}
|
||||
| WITH grant_option_list
|
||||
|
||||
mqh_option:
|
||||
/* empty */ {}
|
||||
| AND WITH MAX_QUERIES_PER_HOUR EQ NUM
|
||||
{
|
||||
Lex->mqh=atoi($5.str);
|
||||
if (Lex->mqh > 65535)
|
||||
YYABORT;
|
||||
grant_option_list:
|
||||
grant_option_list grant_option {}
|
||||
| grant_option {}
|
||||
|
||||
grant_option:
|
||||
GRANT OPTION { Lex->grant |= GRANT_ACL;}
|
||||
| MAX_QUERIES_PER_HOUR EQ NUM
|
||||
{
|
||||
Lex->mqh=atoi($3.str);
|
||||
}
|
||||
|
||||
begin:
|
||||
|
@ -49,7 +49,8 @@
|
||||
X >= 'a' && X <= 'z' ? X-'a'+10 :\
|
||||
'\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 n; /* number of digits yet to be converted */
|
||||
|
Loading…
x
Reference in New Issue
Block a user