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


Docs/manual.texi:
  Fixed Changelog, upgrading to 4.0 and 4.1 TODO sections.
Docs/mysqld_error.txt:
  Added error message.
configure.in:
  Fix for autoconf 2.52
include/my_getopt.h:
  Portability fix.
include/my_global.h:
  Portablity fix.
include/mysqld_error.h:
  New error messages
mysql-test/r/bigint.result:
  Test of unsigned BIGINT values.
mysql-test/r/func_op.result:
  Test of unsigned BIGINT values.
mysql-test/r/varbinary.result:
  Test of unsigned BIGINT values.
mysql-test/t/bigint.test:
  Test of unsigned BIGINT values.
sql/item_func.h:
  Optimized Item_int_func() usage.
sql/lock.cc:
  Cleanup comments
sql/log.cc:
  Cleanup
sql/log_event.cc:
  Cleanup and portability fixes.
sql/log_event.h:
  Cleanup and portability fixes.
sql/mini_client.cc:
  Cleanup and portability fixes.
sql/mysqld.cc:
  Fix for queries-per-hour
sql/repl_failsafe.cc:
  Prepare for making binary log 2G clean.
sql/share/czech/errmsg.txt:
  New error messages
sql/share/danish/errmsg.txt:
  New error messages
sql/share/dutch/errmsg.txt:
  New error messages
sql/share/english/errmsg.txt:
  New error messages
sql/share/estonian/errmsg.txt:
  New error messages
sql/share/french/errmsg.txt:
  New error messages
sql/share/german/errmsg.txt:
  New error messages
sql/share/greek/errmsg.txt:
  New error messages
sql/share/hungarian/errmsg.txt:
  New error messages
sql/share/italian/errmsg.txt:
  New error messages
sql/share/japanese/errmsg.txt:
  New error messages
sql/share/korean/errmsg.txt:
  New error messages
sql/share/norwegian-ny/errmsg.txt:
  New error messages
sql/share/norwegian/errmsg.txt:
  New error messages
sql/share/polish/errmsg.txt:
  New error messages
sql/share/portuguese/errmsg.txt:
  New error messages
sql/share/romanian/errmsg.txt:
  New error messages
sql/share/russian/errmsg.txt:
  New error messages
sql/share/slovak/errmsg.txt:
  New error messages
sql/share/spanish/errmsg.txt:
  New error messages
sql/share/swedish/errmsg.txt:
  New error messages
sql/share/ukrainian/errmsg.txt:
  New error messages
sql/slave.cc:
  Cleanup
sql/slave.h:
  Cleanup
sql/sql_acl.cc:
  Cleanup and removal of possible reserved words
sql/sql_base.cc:
  More DBUG
sql/sql_cache.cc:
  Cleanup & portability fixes
sql/sql_class.h:
  Make binary log 4G clean
sql/sql_delete.cc:
  More DBUG
sql/sql_handler.cc:
  Cleanup & portability fixes
sql/sql_parse.cc:
  Cleanup of queries-per-hours code
sql/sql_rename.cc:
  Add missing DBUG_RETURN
sql/sql_repl.cc:
  Cleanup & portability fixes
sql/sql_select.cc:
  Cleanup & portability fixes
sql/sql_show.cc:
  Cleanup & portability fixes
sql/sql_update.cc:
  Small cleanup of multi-update-code (need second pass)
sql/sql_yacc.yy:
  Changed syntax for GRANT ... QUERIES PER HOUR
strings/str2int.c:
  Cleanup & portability fixes
This commit is contained in:
unknown 2002-01-29 18:32:16 +02:00
parent 741b75b1c7
commit d6a4362687
57 changed files with 1112 additions and 722 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,...)
{

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -230,3 +230,4 @@
"Невозможно выполнить запрос из-за конфликтной блокировки чтения",
"Одновременное использование transactional и non-transactional таблиц отключено",
"Опция '%s' использована дважды",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

@ -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)",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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(&current_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(&current_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(&current_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(&current_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",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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