diff options
| author | monty@hundin.mysql.fi <> | 2002-01-29 18:32:16 +0200 |
|---|---|---|
| committer | monty@hundin.mysql.fi <> | 2002-01-29 18:32:16 +0200 |
| commit | be46289855f01c0d563671beb5135c22b7bad2aa (patch) | |
| tree | dc6d00358536a5dca27f806f929ab5e25a000c92 | |
| parent | e2a5c3e4cd331d9addc2342549e2c47ac7e9cb7a (diff) | |
| download | mariadb-git-be46289855f01c0d563671beb5135c22b7bad2aa.tar.gz | |
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
57 files changed, 1112 insertions, 722 deletions
diff --git a/Docs/manual.texi b/Docs/manual.texi index 6ac76194e5d..4af176c794f 100644 --- a/Docs/manual.texi +++ b/Docs/manual.texi @@ -2965,7 +2965,7 @@ for the records to be deleted, and then use these values to construct the @code{DELETE} statement (@code{DELETE FROM ... WHERE ... IN (key1, key2, ...)}). -The second option is to use interactive SQL to contruct a set of +The second option is to use interactive SQL to construct a set of @code{DELETE} statements automatically, using the MySQL extension @code{CONCAT()} (in lieu of the standard @code{||} operator). For example: @@ -3686,6 +3686,7 @@ For platform-specific bugs, see the sections about compiling and porting. @menu * TODO MySQL 4.0:: Things That Should be in Version 4.0 +* TODO MySQL 4.1:: * TODO future:: Things That Must be Done in the Near Future * TODO sometime:: Things That Have to be Done Sometime * TODO unplanned:: Things we don't Have any Plans to do @@ -3702,30 +3703,30 @@ standard, but with a lot of useful extensions. The challenge is to do this without sacrifying the speed or compromise the code. -@node TODO MySQL 4.0, TODO future, TODO, TODO +@node TODO MySQL 4.0, TODO MySQL 4.1, TODO, TODO @subsection Things That Should be in 4.0 -We have now shifted development to MySQL Server 4.0. Most of the basic -things we want to have in 4.0 are already done. The target is to quickly -implement the rest of the following features and then shift development -to MySQL Server 4.1. @xref{MySQL 4.0 In A Nutshell}. +We have now in the final stages one the development of the MySQL Server +4.0. server. The target is to quickly implement the rest of the +following features and then shift development to MySQL Server +4.1. @xref{MySQL 4.0 In A Nutshell}. The news section for 4.0 includes a list of the features we have already implemented in the 4.0 tree. @xref{News-4.0.x}. -This section lists features not yet implemented in the current -version of MySQL Server 4.0, which will however be implemented in -later versions of MySQL 4.0. This being very volatile information, -please consider this list valid only if you are reading it from -the MySQL web site (@uref{http://www.mysql.com/}). +This section lists features not yet implemented in the current version +of MySQL Server 4.0, which will however be implemented in later versions +of MySQL 4.0. This being very volatile information, please consider this +list valid only if you are reading it from the MySQL web site +(@uref{http://www.mysql.com/}). @itemize @bullet @item Allow users to change startup options without taking down the server. @item -Fail safe replication. +Better command line argument handling. @item -New key cache +New key cache, which will give better performance when using many threads. @item New table definition file format (@code{.frm} files) This will enable us to not run out of bits when adding more table options. One will still @@ -3733,52 +3734,40 @@ 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. -@item -Replication should work with @code{RAND()} and user variables @code{@@var}. -@item -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 -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. +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 -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 -Add @code{record_in_range()} method to @code{MERGE} tables to be -able to choose the right index when there is many to choose from. We should -also extend the info interface to get the key distribution for each index, -of @code{analyze} is run on all sub tables. -@item -@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 +@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 -Atomic multi-table updates, eg @code{update items,month set -items.price=month.price where items.id=month.id;}; +Foreign keys, including cascading delete. +@item +Fail safe replication. +@item +Replication should work with @code{RAND()} and user variables @code{@@var}. +@item +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 @@ -3791,20 +3780,46 @@ SELECT a.col1, b.col2 This could be done by automatically creating temporary tables for the derived tables for the duration of the query. @item -Add @code{PREPARE} of statements and sending of parameters to @code{mysqld}. +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 -Extend the client/server protocol to support warnings. +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 -Add options to the client/server protocol to get progress notes -for long running commands. +Add @code{record_in_range()} method to @code{MERGE} tables to be +able to choose the right index when there is many to choose from. We should +also extend the info interface to get the key distribution for each index, +of @code{analyze} is run on all sub tables. +@item +@code{RENAME TABLE} on a table used in an active @code{MERGE} table may +corrupt the table. +@item +A faster, smaller embedded MySQL library. (Compatible with the old one) +@item +Stable openssl support. (MySQL 4.0 supports rudimentary, not 100 % tested +support for openssl). +@item +Add support for sorting on @code{UNICODE}. +@item +Character set casts and syntax for handling multiple character sets. +@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. +@item +Help for all commands from the client. +@item +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 diff --git a/Docs/my_sys.txt b/Docs/my_sys.txt new file mode 100644 index 00000000000..85ffc13ecb4 --- /dev/null +++ b/Docs/my_sys.txt @@ -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. diff --git a/Docs/mysqld_error.txt b/Docs/mysqld_error.txt index 14f9e426fc0..7a5b6cf38d0 100644 --- a/Docs/mysqld_error.txt +++ b/Docs/mysqld_error.txt @@ -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", diff --git a/configure.in b/configure.in index d1728dab674..50000a808b7 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/include/my_getopt.h b/include/my_getopt.h index 3132d6a1672..fef8aacd75a 100644 --- a/include/my_getopt.h +++ b/include/my_getopt.h @@ -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 */ diff --git a/include/my_global.h b/include/my_global.h index 40e70c521eb..a5fe99d5271 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -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 diff --git a/include/mysqld_error.h b/include/mysqld_error.h index b77a194e72c..c910078331e 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -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 diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index b7eaa179484..f2cb6437f8f 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -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 diff --git a/mysql-test/r/func_op.result b/mysql-test/r/func_op.result index dca85a77c09..9f49b5809df 100644 --- a/mysql-test/r/func_op.result +++ b/mysql-test/r/func_op.result @@ -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 diff --git a/mysql-test/r/varbinary.result b/mysql-test/r/varbinary.result index 1596ad15810..a63db14b736 100644 --- a/mysql-test/r/varbinary.result +++ b/mysql-test/r/varbinary.result @@ -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 diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index e779b0fd49b..cec3e1ca45c 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -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; diff --git a/sql/item_func.h b/sql/item_func.h index f7794028998..578c3034b32 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -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;} }; diff --git a/sql/lock.cc b/sql/lock.cc index 9f4f23b01e3..5d2856278b6 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -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); diff --git a/sql/log.cc b/sql/log.cc index 17b6ef4344c..13ebbd9a3e7 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -370,6 +370,7 @@ err: return error; } + int MYSQL_LOG::reset_logs(THD* thd) { LOG_INFO linfo; @@ -403,6 +404,7 @@ err: return error; } + int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli) { // pre-conditions @@ -410,17 +412,17 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli) DBUG_ASSERT(index_file >= 0); DBUG_ASSERT(rli->slave_running == 1); DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->relay_log_name)); - // assume that we have previously read the first log and - // stored it in rli->relay_log_name + /* + Assume that we have previously read the first log and + stored it in rli->relay_log_name + */ DBUG_ASSERT(rli->linfo.index_file_offset == strlen(rli->relay_log_name) + 1); - int tmp_fd; - - char* fname, *io_buf; int error = 0; - if (!(fname = (char*)my_malloc(IO_SIZE+FN_REFLEN, MYF(MY_WME)))) + + if (!(fname= (char*) my_malloc(IO_SIZE+FN_REFLEN, MYF(MY_WME)))) return 1; pthread_mutex_lock(&LOCK_index); my_seek(index_file,rli->linfo.index_file_offset, @@ -436,21 +438,22 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli) for (;;) { int bytes_read; - bytes_read = my_read(index_file, io_buf, IO_SIZE, MYF(0)); - if (bytes_read < 0) // error + bytes_read = my_read(index_file, (byte*) io_buf, IO_SIZE, MYF(0)); + if (bytes_read < 0) // error { error=1; goto err; } if (!bytes_read) - break; // end of file + break; // end of file // otherwise, we've read something and need to write it out - if (my_write(tmp_fd, io_buf, bytes_read, MYF(MY_WME|MY_NABP))) + if (my_write(tmp_fd, (byte*) io_buf, bytes_read, MYF(MY_WME|MY_NABP))) { error=1; goto err; } } + err: if (tmp_fd) my_close(tmp_fd, MYF(MY_WME)); @@ -476,18 +479,20 @@ err: strnmov(rli->relay_log_name,rli->linfo.log_file_name, sizeof(rli->relay_log_name)); } - // no need to free io_buf because we allocated both fname and io_buf in - // one malloc() + /* + No need to free io_buf because we allocated both fname and io_buf in + one malloc() + */ + err2: pthread_mutex_unlock(&LOCK_index); my_free(fname, MYF(MY_WME)); return error; } + int MYSQL_LOG::purge_logs(THD* thd, const char* to_log) { - if (index_file < 0) return LOG_INFO_INVALID; - if (no_rotate) return LOG_INFO_PURGE_NO_ROTATE; int error; char fname[FN_REFLEN]; char *p; @@ -498,6 +503,10 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log) LINT_INIT(purge_offset); IO_CACHE io_cache; + if (index_file < 0) + return LOG_INFO_INVALID; + if (no_rotate) + return LOG_INFO_PURGE_NO_ROTATE; pthread_mutex_lock(&LOCK_index); if (init_io_cache(&io_cache,index_file, IO_SIZE*2, READ_CACHE, (my_off_t) 0, @@ -569,9 +578,10 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log) sql_print_error("Error deleting %s during purge", l); } - // if we get killed -9 here, the sysadmin would have to do a small - // vi job on the log index file after restart - otherwise, this should - // be safe + /* + If we get killed -9 here, the sysadmin would have to edit + the log index file after restart - otherwise, this should be safe + */ #ifdef HAVE_FTRUNCATE if (ftruncate(index_file,0)) { @@ -737,14 +747,14 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...) pthread_mutex_lock(&LOCK_log); do { - if (my_b_append(&log_file,buf,len)) + if (my_b_append(&log_file,(byte*) buf,len)) { error = 1; break; } } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint))); - if ((uint)my_b_append_tell(&log_file) > max_binlog_size) + if ((uint) my_b_append_tell(&log_file) > max_binlog_size) { new_file(1); } @@ -755,6 +765,7 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...) return error; } + bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, const char *format,...) { diff --git a/sql/log_event.cc b/sql/log_event.cc index 4d6d5341312..648e9175e13 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -26,17 +26,19 @@ #include <assert.h> -inline int my_b_safe_write(IO_CACHE* file, const char* 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 +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 + */ 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; diff --git a/sql/log_event.h b/sql/log_event.h index 686d353d8bb..089d9589763 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -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); diff --git a/sql/mini_client.cc b/sql/mini_client.cc index a5879081566..c31fa573fea 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -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"); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b6e33a32b74..983218e42d2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -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) diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index eabba9c68fc..6cc7ef7404b 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -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; diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index c78da67f3de..950ca4f6623 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -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)", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 9a7dffb4ae2..d87ed4ee629 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -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)", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index dedf41ee394..c84c49dadc6 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -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)", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 50cc4095038..5033449c266 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -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)", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 1e0fa15d2c0..6a83468eae5 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -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)", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 11f70c7a997..cf3e3e845e4 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -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)", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index f277a4f08e8..19d46fabab8 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -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)", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index f36f2db98cf..f9b4f137f82 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -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)", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 2609e33a419..38877371243 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -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)", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index df091f9549e..e8cfd5a63a9 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -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)", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index f4d0e6069e4..98bc099954f 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -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)", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index d58c3db406e..f6cc890cb39 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -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)", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index b96e9a53e10..adffc27949f 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -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)", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index bf2afdb1c9b..09a1ea4684c 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -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)", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 69a619045e5..12a9bd358b5 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -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)", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 964c399628f..b7feb0a7b0d 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -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)", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 9fa6ceebaa4..8e48cabfc39 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -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)", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index cde0afca01f..8ed33ec21a0 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -230,3 +230,4 @@ "îÅ×ÏÚÍÏÖÎÏ ×ÙÐÏÌÎÉÔØ ÚÁÐÒÏÓ ÉÚ-ÚÁ ËÏÎÆÌÉËÔÎÏÊ ÂÌÏËÉÒÏ×ËÉ ÞÔÅÎÉÑ", "ïÄÎÏ×ÒÅÍÅÎÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ transactional É non-transactional ÔÁÂÌÉà ÏÔËÌÀÞÅÎÏ", "ïÐÃÉÑ '%s' ÉÓÐÏÌØÚÏ×ÁÎÁ Ä×ÁÖÄÙ", +"User '%-64s' has exceeded the '%s' resource (current value: %ld)", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 6814a34ef2f..06503cdf69e 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -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)", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 0f2b963b902..4240581c5b8 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -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)", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 53ab39f1544..e774f4a2c5c 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -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)", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index b2dfd1c887f..c4c89433331 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -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)", diff --git a/sql/slave.cc b/sql/slave.cc index 59e07040528..16c6751f853 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -268,7 +268,7 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, bool just_reset, const char** errmsg) pthread_mutex_lock(&rli->data_lock); rli->pending=0; rli->master_log_name[0]=0; - rli->master_log_pos=0; // 0 means uninitialized + rli->master_log_pos=0; // 0 means uninitialized if (rli->relay_log.reset_logs(rli->sql_thd) || rli->relay_log.find_first_log(&rli->linfo,"")) { @@ -990,7 +990,7 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) } if (init_relay_log_pos(rli,"",4,0/*no data mutex*/,&msg)) goto err; - rli->master_log_pos = 0; // uninitialized + rli->master_log_pos = 0; // uninitialized rli->info_fd = info_fd; } else // file exists @@ -1049,6 +1049,7 @@ err: return 1; } + int init_master_info(MASTER_INFO* mi, const char* master_info_fname, const char* slave_info_fname) { @@ -1058,14 +1059,16 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, return 1; mi->rli.mi = mi; mi->ignore_stop_event=0; - int fd,length,error; + int fd,error; MY_STAT stat_area; char fname[FN_REFLEN+128]; const char *msg; fn_format(fname, master_info_fname, mysql_data_home, "", 4+32); - // we need a mutex while we are changing master info parameters to - // keep other threads from reading bogus info + /* + We need a mutex while we are changing master info parameters to + keep other threads from reading bogus info + */ pthread_mutex_lock(&mi->data_lock); fd = mi->fd; @@ -1089,7 +1092,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, return 1; } mi->master_log_name[0] = 0; - mi->master_log_pos = 4; // skip magic number + mi->master_log_pos = 4; // skip magic number mi->fd = fd; if (master_host) @@ -1119,20 +1122,18 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, mi->fd = fd; if (init_strvar_from_file(mi->master_log_name, - sizeof(mi->master_log_name), &mi->file, - (char*)"") || - init_intvar_from_file((int*)&mi->master_log_pos, &mi->file, 4) - || - init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, - master_host) || - init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, - master_user) || - init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file, - master_password) || - init_intvar_from_file((int*)&mi->port, &mi->file, master_port) || - init_intvar_from_file((int*)&mi->connect_retry, &mi->file, - master_connect_retry) - ) + sizeof(mi->master_log_name), &mi->file, + (char*)"") || + init_intvar_from_file((int*)&mi->master_log_pos, &mi->file, 4) || + init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, + master_host) || + init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, + master_user) || + init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file, + master_password) || + init_intvar_from_file((int*)&mi->port, &mi->file, master_port) || + init_intvar_from_file((int*)&mi->connect_retry, &mi->file, + master_connect_retry)) { msg="Error reading master configuration"; goto err; @@ -1140,8 +1141,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, } mi->inited = 1; - // now change the cache from READ to WRITE - must do this - // before flush_master_info + // now change cache READ -> WRITE - must do this before flush_master_info reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1); error=test(flush_master_info(mi)); pthread_mutex_unlock(&mi->data_lock); @@ -1250,7 +1250,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi) net_store_data(packet, (uint32)mi->rli.last_slave_errno); net_store_data(packet, mi->rli.last_slave_error); net_store_data(packet, mi->rli.slave_skip_counter); - net_store_data(packet, (longlong)mi->rli.master_log_pos); + net_store_data(packet, (longlong) mi->rli.master_log_pos); pthread_mutex_unlock(&mi->rli.data_lock); pthread_mutex_unlock(&mi->data_lock); @@ -1408,7 +1408,8 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi) int len; int binlog_flags = 0; // for now char* logname = mi->master_log_name; - int4store(buf, mi->master_log_pos); + // TODO if big log files: Change next to int8store() + int4store(buf, (longlong) mi->master_log_pos); int2store(buf + 4, binlog_flags); int4store(buf + 6, server_id); len = (uint) strlen(logname); @@ -1521,7 +1522,6 @@ point. If you are sure that your master is ok, run this query manually on the\ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) { - const char *error_msg; DBUG_ASSERT(rli->sql_thd==thd); Log_event * ev = next_event(rli); DBUG_ASSERT(rli->sql_thd==thd); @@ -1582,7 +1582,7 @@ This may also be a network problem, or just a bug in the master or slave code.\ pthread_handler_decl(handle_slave_io,arg) { #ifndef DBUG_OFF - slave_begin: +slave_begin: #endif THD *thd; // needs to be first for thread_stack MYSQL *mysql = NULL ; @@ -1604,12 +1604,12 @@ pthread_handler_decl(handle_slave_io,arg) pthread_detach_this_thread(); if (init_slave_thread(thd, SLAVE_THD_IO)) - { - pthread_cond_broadcast(&mi->start_cond); - pthread_mutex_unlock(&mi->run_lock); - sql_print_error("Failed during slave I/O thread initialization"); - goto err; - } + { + pthread_cond_broadcast(&mi->start_cond); + pthread_mutex_unlock(&mi->run_lock); + sql_print_error("Failed during slave I/O thread initialization"); + goto err; + } mi->io_thd = thd; thd->thread_stack = (char*)&thd; // remember where our stack is threads.append(thd); @@ -1633,11 +1633,11 @@ pthread_handler_decl(handle_slave_io,arg) #endif // we can get killed during safe_connect if (!safe_connect(thd, mysql, mi)) - sql_print_error("Slave I/O thread: connected to master '%s@%s:%d',\ + sql_print_error("Slave I/O thread: connected to master '%s@%s:%d',\ replication started in log '%s' at position %s", mi->user, - mi->host, mi->port, - IO_RPL_LOG_NAME, - llstr(mi->master_log_pos,llbuff)); + mi->host, mi->port, + IO_RPL_LOG_NAME, + llstr(mi->master_log_pos,llbuff)); else { sql_print_error("Slave I/O thread killed while connecting to master"); @@ -1649,14 +1649,14 @@ connected: thd->slave_net = &mysql->net; thd->proc_info = "Checking master version"; if (check_master_version(mysql, mi)) - { goto err; - } if (!mi->old_format) { - // register ourselves with the master - // if fails, this is not fatal - we just print the error message and go - // on with life + /* + Register ourselves with the master. + If fails, this is not fatal - we just print the error message and go + on with life. + */ thd->proc_info = "Registering slave on master"; if (register_slave_on_master(mysql) || update_slave_list(mysql)) goto err; @@ -1664,122 +1664,124 @@ connected: while (!slave_killed(thd,mi)) { - thd->proc_info = "Requesting binlog dump"; - if (request_dump(mysql, mi)) - { - sql_print_error("Failed on request_dump()"); - if(slave_killed(thd,mi)) - { - sql_print_error("Slave I/O thread killed while requesting master \ + thd->proc_info = "Requesting binlog dump"; + if (request_dump(mysql, mi)) + { + sql_print_error("Failed on request_dump()"); + if(slave_killed(thd,mi)) + { + sql_print_error("Slave I/O thread killed while requesting master \ dump"); - goto err; - } + goto err; + } - thd->proc_info = "Waiiting to reconnect after a failed dump request"; - mc_end_server(mysql); - // first time retry immediately, assuming that we can recover - // right away - if first time fails, sleep between re-tries - // hopefuly the admin can fix the problem sometime - if (retried_once) - safe_sleep(thd, mi, mi->connect_retry); - else - retried_once = 1; + thd->proc_info = "Waiiting to reconnect after a failed dump request"; + mc_end_server(mysql); + /* + First time retry immediately, assuming that we can recover + right away - if first time fails, sleep between re-tries + hopefuly the admin can fix the problem sometime + */ + if (retried_once) + safe_sleep(thd, mi, mi->connect_retry); + else + retried_once = 1; - if (slave_killed(thd,mi)) - { - sql_print_error("Slave I/O thread killed while retrying master \ + if (slave_killed(thd,mi)) + { + sql_print_error("Slave I/O thread killed while retrying master \ dump"); - goto err; - } + goto err; + } - thd->proc_info = "Reconnecting after a failed dump request"; - sql_print_error("Slave I/O thread: failed dump request, \ + thd->proc_info = "Reconnecting after a failed dump request"; + sql_print_error("Slave I/O thread: failed dump request, \ reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME, - llstr(mi->master_log_pos,llbuff)); - if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi)) - { - sql_print_error("Slave I/O thread killed during or \ + llstr(mi->master_log_pos,llbuff)); + if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi)) + { + sql_print_error("Slave I/O thread killed during or \ after reconnect"); - goto err; - } + goto err; + } - goto connected; - } + goto connected; + } - while (!slave_killed(thd,mi)) - { - thd->proc_info = "Reading master update"; - ulong event_len = read_event(mysql, mi); - if (slave_killed(thd,mi)) - { - sql_print_error("Slave I/O thread killed while reading event"); - goto err; - } + while (!slave_killed(thd,mi)) + { + thd->proc_info = "Reading master update"; + ulong event_len = read_event(mysql, mi); + if (slave_killed(thd,mi)) + { + sql_print_error("Slave I/O thread killed while reading event"); + goto err; + } - if (event_len == packet_error) - { - if (mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE) - { - sql_print_error("Log entry on master is longer than \ -max_allowed_packet on slave. Slave thread will be aborted. If the entry is \ -really supposed to be that long, restart the server with a higher value of \ -max_allowed_packet. The current value is %ld", max_allowed_packet); - goto err; - } + if (event_len == packet_error) + { + if (mc_mysql_errno(mysql) == ER_NET_PACKET_TOO_LARGE) + { + sql_print_error("Log entry on master is longer than \ +max_allowed_packet (%ld) on slave. Slave thread will be aborted. If the entry \ +is correct, restart the server with a higher value of max_allowed_packet", + max_allowed_packet); + goto err; + } - thd->proc_info = "Waiting to reconnect after a failed read"; - mc_end_server(mysql); - if (retried_once) // punish repeat offender with sleep - safe_sleep(thd,mi,mi->connect_retry); - else - retried_once = 1; + thd->proc_info = "Waiting to reconnect after a failed read"; + mc_end_server(mysql); + if (retried_once) // punish repeat offender with sleep + safe_sleep(thd,mi,mi->connect_retry); + else + retried_once = 1; - if (slave_killed(thd,mi)) - { - sql_print_error("Slave I/O thread killed while waiting to \ + if (slave_killed(thd,mi)) + { + sql_print_error("Slave I/O thread killed while waiting to \ reconnect after a failed read"); - goto err; - } - thd->proc_info = "Reconnecting after a failed read"; - sql_print_error("Slave I/O thread: Failed reading log event, \ + goto err; + } + thd->proc_info = "Reconnecting after a failed read"; + sql_print_error("Slave I/O thread: Failed reading log event, \ reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME, - llstr(mi->master_log_pos, llbuff)); - if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi)) - { - sql_print_error("Slave I/O thread killed during or after a \ + llstr(mi->master_log_pos, llbuff)); + if (safe_reconnect(thd, mysql, mi) || slave_killed(thd,mi)) + { + sql_print_error("Slave I/O thread killed during or after a \ reconnect done to recover from failed read"); - goto err; - } - goto connected; - } // if(event_len == packet_error) + goto err; + } + goto connected; + } // if(event_len == packet_error) - thd->proc_info = "Queueing event from master"; - if (queue_event(mi,(const char*)mysql->net.read_pos + 1, - (uint)event_len)) - { - sql_print_error("Slave I/O thread could not queue event \ + thd->proc_info = "Queueing event from master"; + if (queue_event(mi,(const char*)mysql->net.read_pos + 1, + event_len)) + { + sql_print_error("Slave I/O thread could not queue event \ from master"); - goto err; - } - // TODO: check debugging abort code + goto err; + } + // TODO: check debugging abort code #ifndef DBUG_OFF - if (abort_slave_event_count && !--events_till_abort) - { - sql_print_error("Slave I/O thread: debugging abort"); - goto err; - } + if (abort_slave_event_count && !--events_till_abort) + { + sql_print_error("Slave I/O thread: debugging abort"); + goto err; + } #endif - } // while(!slave_killed(thd,mi)) - read/exec loop + } // while(!slave_killed(thd,mi)) - read/exec loop } // while(!slave_killed(thd,mi)) - slave loop // error = 0; - err: +err: // print the current replication position sql_print_error("Slave I/O thread exiting, read up to log '%s', position %s", IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff)); thd->query = thd->db = 0; // extra safety if(mysql) - mc_mysql_close(mysql); + mc_mysql_close(mysql); thd->proc_info = "Waiting for slave mutex on exit"; pthread_mutex_lock(&mi->run_lock); mi->slave_running = 0; @@ -1803,12 +1805,13 @@ from master"); DBUG_RETURN(0); // Can't return anything here } + /* slave SQL logic thread */ pthread_handler_decl(handle_slave_sql,arg) { #ifndef DBUG_OFF - slave_begin: +slave_begin: #endif THD *thd; /* needs to be first for thread_stack */ MYSQL *mysql = NULL ; @@ -1832,14 +1835,16 @@ pthread_handler_decl(handle_slave_sql,arg) pthread_detach_this_thread(); if (init_slave_thread(thd, SLAVE_THD_SQL)) - { - // TODO: this is currently broken - slave start and change master - // will be stuck if we fail here - pthread_cond_broadcast(&rli->start_cond); - pthread_mutex_unlock(&rli->run_lock); - sql_print_error("Failed during slave thread initialization"); - goto err; - } + { + /* + TODO: this is currently broken - slave start and change master + will be stuck if we fail here + */ + pthread_cond_broadcast(&rli->start_cond); + pthread_mutex_unlock(&rli->run_lock); + sql_print_error("Failed during slave thread initialization"); + goto err; + } thd->thread_stack = (char*)&thd; // remember where our stack is thd->temporary_tables = rli->save_temporary_tables; // restore temp tables threads.append(thd); @@ -1876,7 +1881,7 @@ log '%s' at position %s,relay log: name='%s',pos='%s'", RPL_LOG_NAME, if (!slave_killed(thd,rli)) sql_print_error("\ Error running query, slave SQL thread aborted. Fix the problem, and restart \ -the slave SQL thread with \"mysqladmin start-slave\". We stopped at log \ +the slave SQL thread with \"SLAVE START\". We stopped at log \ '%s' position %s", RPL_LOG_NAME, llstr(rli->master_log_pos, llbuff)); goto err; @@ -1895,8 +1900,11 @@ the slave SQL thread with \"mysqladmin start-slave\". We stopped at log \ DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun rli->slave_running = 0; rli->save_temporary_tables = thd->temporary_tables; - //TODO: see if we can do this conditionally in next_event() instead - // to avoid unneeded position re-init + + /* + TODO: see if we can do this conditionally in next_event() instead + to avoid unneeded position re-init + */ rli->log_pos_current=0; thd->temporary_tables = 0; // remove tempation from destructor to close them DBUG_ASSERT(thd->net.buff != 0); @@ -1918,6 +1926,7 @@ the slave SQL thread with \"mysqladmin start-slave\". We stopped at log \ DBUG_RETURN(0); // Can't return anything here } + // We assume we already locked mi->data_lock static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev) { @@ -1929,39 +1938,41 @@ static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev) mi->master_log_name[rev->ident_len] = 0; mi->master_log_pos = rev->pos; #ifndef DBUG_OFF - /* if we do not do this, we will be getting the first - rotate event forever, so - we need to not disconnect after one - */ - if (disconnect_slave_event_count) - events_till_disconnect++; + /* + If we do not do this, we will be getting the first + rotate event forever, so we need to not disconnect after one. + */ + if (disconnect_slave_event_count) + events_till_disconnect++; #endif - return 0; + return 0; } -// TODO: verify the issue with stop events, see if we need them at all -// in the relay log -// TODO: test this code before release - it has to be tested on a separte -// setup with 3.23 master -static int queue_old_event(MASTER_INFO* mi, const char* buf, - uint event_len) +/* + TODO: verify the issue with stop events, see if we need them at all + in the relay log + TODO: test this code before release - it has to be tested on a separte + setup with 3.23 master +*/ + +static int queue_old_event(MASTER_INFO *mi, const char *buf, + ulong event_len) { - const char* errmsg = 0; + const char *errmsg = 0; bool inc_pos = 1; bool processed_stop_event = 0; - Log_event* ev = Log_event::read_log_event(buf,event_len, &errmsg, - 1/*old format*/); + Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg, + 1 /*old format*/ ); if (unlikely(!ev)) { sql_print_error("Read invalid event from master: '%s',\ - master could be corrupt but a more likely cause of this is a bug", + master could be corrupt but a more likely cause of this is a bug", errmsg); return 1; } pthread_mutex_lock(&mi->data_lock); ev->log_pos = mi->master_log_pos; - switch (ev->get_type_code()) - { + switch (ev->get_type_code()) { case ROTATE_EVENT: if (unlikely(process_io_rotate(mi,(Rotate_log_event*)ev))) { @@ -2003,9 +2014,12 @@ static int queue_old_event(MASTER_INFO* mi, const char* buf, return 0; } -// TODO: verify the issue with stop events, see if we need them at all -// in the relay log -int queue_event(MASTER_INFO* mi,const char* buf,uint event_len) +/* + TODO: verify the issue with stop events, see if we need them at all + in the relay log +*/ + +int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) { int error=0; bool inc_pos = 1; @@ -2015,10 +2029,11 @@ int queue_event(MASTER_INFO* mi,const char* buf,uint event_len) pthread_mutex_lock(&mi->data_lock); - // TODO: figure out if other events in addition to Rotate - // require special processing - switch (buf[EVENT_TYPE_OFFSET]) - { + /* + TODO: figure out if other events in addition to Rotate + require special processing + */ + switch (buf[EVENT_TYPE_OFFSET]) { case STOP_EVENT: processed_stop_event=1; break; @@ -2048,22 +2063,23 @@ int queue_event(MASTER_INFO* mi,const char* buf,uint event_len) return error; } + void end_relay_log_info(RELAY_LOG_INFO* rli) { if (!rli->inited) return; if (rli->info_fd >= 0) - { - end_io_cache(&rli->info_file); - (void)my_close(rli->info_fd, MYF(MY_WME)); - rli->info_fd = -1; - } + { + end_io_cache(&rli->info_file); + (void)my_close(rli->info_fd, MYF(MY_WME)); + rli->info_fd = -1; + } if (rli->cur_log_fd >= 0) - { - end_io_cache(&rli->cache_buf); - (void)my_close(rli->cur_log_fd, MYF(MY_WME)); - rli->cur_log_fd = -1; - } + { + end_io_cache(&rli->cache_buf); + (void)my_close(rli->cur_log_fd, MYF(MY_WME)); + rli->cur_log_fd = -1; + } rli->inited = 0; rli->log_pos_current=0; rli->relay_log.close(1); @@ -2075,10 +2091,12 @@ static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi) return connect_to_master(thd, mysql, mi, 0); } + /* Try to connect until successful or slave killed or we have retried master_retry_count times */ + static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, bool reconnect) { @@ -2091,9 +2109,9 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, events_till_disconnect = disconnect_slave_event_count; #endif while (!(slave_was_killed = slave_killed(thd,mi)) && - (reconnect ? mc_mysql_reconnect(mysql) : + (reconnect ? mc_mysql_reconnect(mysql) != 0 : !mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0, - mi->port, 0, 0))) + mi->port, 0, 0))) { /* Don't repeat last error */ if (mc_mysql_errno(mysql) != last_errno) @@ -2105,10 +2123,11 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, mi->connect_retry); } safe_sleep(thd,mi,mi->connect_retry); - /* by default we try forever. The reason is that failure will trigger - master election, so if the user did not set master_retry_count we - do not want to have electioin triggered on the first failure to - connect + /* + By default we try forever. The reason is that failure will trigger + master election, so if the user did not set master_retry_count we + do not want to have electioin triggered on the first failure to + connect */ if (master_retry_count && err_count++ == master_retry_count) { @@ -2124,14 +2143,14 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, if (reconnect) sql_print_error("Slave: connected to master '%s@%s:%d',\ replication resumed in log '%s' at position %s", mi->user, - mi->host, mi->port, - IO_RPL_LOG_NAME, - llstr(mi->master_log_pos,llbuff)); + mi->host, mi->port, + IO_RPL_LOG_NAME, + llstr(mi->master_log_pos,llbuff)); else { change_rpl_status(RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE); mysql_log.write(thd, COM_CONNECT_OUT, "%s@%s:%d", - mi->user, mi->host, mi->port); + mi->user, mi->host, mi->port); } #ifdef SIGNAL_WITH_VIO_CLOSE thd->set_active_vio(mysql->net.vio); @@ -2141,6 +2160,7 @@ replication resumed in log '%s' at position %s", mi->user, return slave_was_killed; } + /* Try to connect until successful or slave killed or we have retried master_retry_count times @@ -2172,7 +2192,7 @@ IO_CACHE* reopen_relay_log(RELAY_LOG_INFO* rli, const char** errmsg) IO_CACHE* cur_log = rli->cur_log=&rli->cache_buf; DBUG_ASSERT(rli->cur_log_fd == -1); if ((rli->cur_log_fd=open_binlog(cur_log,rli->relay_log_name, - errmsg))<0) + errmsg)) <0) return 0; my_b_seek(cur_log,rli->relay_log_pos); return cur_log; @@ -2188,29 +2208,36 @@ Log_event* next_event(RELAY_LOG_INFO* rli) bool was_killed; DBUG_ASSERT(thd != 0); - // For most operations we need to protect rli members with data_lock, - // so we will hold it for the most of the loop below - // However, we will release it whenever it is worth the hassle, - // and in the cases when we go into a pthread_cond_wait() with the - // non-data_lock mutex + /* + For most operations we need to protect rli members with data_lock, + so we will hold it for the most of the loop below + However, we will release it whenever it is worth the hassle, + and in the cases when we go into a pthread_cond_wait() with the + non-data_lock mutex + */ pthread_mutex_lock(&rli->data_lock); - for (;!(was_killed=slave_killed(thd,rli));) - { - // 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. + 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. + */ 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; } } diff --git a/sql/slave.h b/sql/slave.h index 9632b108ab5..db12ab91618 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -33,8 +33,11 @@ extern my_string opt_relay_logname, opt_relaylog_index_name; extern bool opt_skip_slave_start; struct st_master_info; -// TODO: this needs to be redone, but for now it does not matter since -// we do not have multi-master yet. +/* + TODO: this needs to be redone, but for now it does not matter since + we do not have multi-master yet. +*/ + #define LOCK_ACTIVE_MI { pthread_mutex_lock(&LOCK_active_mi); \ ++active_mi_in_use; \ pthread_mutex_unlock(&LOCK_active_mi);} @@ -62,50 +65,64 @@ struct st_master_info; To clean up, call end_relay_log_info() */ + typedef struct st_relay_log_info { - // info_fd - file descriptor of the info file. set only during - // initialization or clean up - safe to read anytime - // cur_log_fd - file descriptor of the current read relay log, protected by - // data_lock + /*** The following variables can only be read when protect by data lock ****/ + /* + info_fd - file descriptor of the info file. set only during + initialization or clean up - safe to read anytime + cur_log_fd - file descriptor of the current read relay log + */ File info_fd,cur_log_fd; - - // IO_CACHE of the info file - set only during init or end, safe to read - // anytime - IO_CACHE info_file; - - // name of current read relay log - protected by data_lock + // name of current read relay log char relay_log_name[FN_REFLEN]; - - // master log name corresponding to current read position - protected by - // data lock + // 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; - // original log position of last processed event - protected by data_lock - volatile uint32 master_log_pos; + // 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; - // 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 - - diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 091db4e4b39..7cfe801e6f0 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -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); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a8be2d8b8f5..a5116fa0e20 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -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; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 73b15ff3cf1..5b2c9673fdc 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -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; diff --git a/sql/sql_class.h b/sql/sql_class.h index 1d8fa1554d3..4e12cefa271 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -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(); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 2a7824eae68..a155abc522b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -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"; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 0c6b5599519..8f9d3474ce2 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -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) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3bcade84cd0..4db3b7f7211 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -55,7 +55,9 @@ extern "C" pthread_mutex_t THR_LOCK_keycache; extern "C" int gethostname(char *name, int namelen); #endif -static int check_for_max_user_connections(const char *user, const char *host, uint max); +static int check_for_max_user_connections(const char *user, const char *host, uint max_questions); +static bool check_mqh(THD *thd, const char *user, const char *host, + uint max_questions); static void decrease_user_connections(const char *user, const char *host); static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables); @@ -121,101 +123,22 @@ extern pthread_mutex_t LOCK_user_conn; struct user_conn { char *user; - uint len, connections, questions, max; + uint len, connections, questions, max_questions; time_t intime; }; -static byte* get_key_conn(user_conn *buff, uint *length, - my_bool not_used __attribute__((unused))) -{ - *length=buff->len; - return (byte*) buff->user; -} - -#define DEF_USER_COUNT 50 - -static void free_user(struct user_conn *uc) -{ - my_free((char*) uc,MYF(0)); -} - -/* -** Check if maximum queries per hour limit has been reached -** returns 0 if OK. -*/ - -static bool check_mqh(THD *thd, const char *user, const char *host,uint max) -{ - uint temp_len; - char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2]; - struct user_conn *uc; - if (!user) - user=""; - if (!host) - host=""; - temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host, - NullS) - temp_user); -//This would be MUCH faster if there was already temp_user made in THD !!! May I ?? - (void) pthread_mutex_lock(&LOCK_user_conn); - uc = (struct user_conn *) hash_search(&hash_user_connections, - (byte*) temp_user, temp_len); - if (uc) /* user found ; check for no. of queries */ - { - bool my_start = thd->start_time != 0; - time_t check_time = (my_start) ? thd->start_time : time(NULL); - if (check_time - uc->intime >= 3600) - { - uc->questions=(uint)my_start; - uc->intime=check_time; - } - else if (uc->max && ++(uc->questions) > uc->max) - { - (void) pthread_mutex_unlock(&LOCK_user_conn); - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); // change this to appropriate message - return 1; - } - } - else - { - struct user_conn *uc= ((struct user_conn*) - my_malloc(sizeof(struct user_conn) + temp_len+1, - MYF(MY_WME))); - if (!uc) - { - send_error(¤t_thd->net, 0, NullS); // Out of memory - (void) pthread_mutex_unlock(&LOCK_user_conn); - return 1; - } - uc->user=(char*) (uc+1); - memcpy(uc->user,temp_user,temp_len+1); - uc->len = temp_len; - uc->connections = 1; - uc->questions=0; - uc->max=max; - uc->intime=current_thd->thr_create_time; - if (hash_insert(&hash_user_connections, (byte*) uc)) - { - my_free((char*) uc,0); - send_error(¤t_thd->net, 0, NullS); // Out of memory - (void) pthread_mutex_unlock(&LOCK_user_conn); - return 1; - } - } - (void) pthread_mutex_unlock(&LOCK_user_conn); - return 0; -} /* -** Check if user is ok -** Updates: -** thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access + Check if user is ok + Updates: + thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access */ static bool check_user(THD *thd,enum_server_command command, const char *user, const char *passwd, const char *db, bool check_count) { NET *net= &thd->net; - uint max=0; + uint max_questions=0; thd->db=0; thd->db_length=0; @@ -228,7 +151,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, passwd, thd->scramble, &thd->priv_user, protocol_version == 9 || !(thd->client_capabilities & - CLIENT_LONG_PASSWORD),&max); + CLIENT_LONG_PASSWORD),&max_questions); DBUG_PRINT("info", ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'", thd->client_capabilities, thd->max_packet_length, @@ -259,8 +182,6 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, return(1); } } - if (mqh_used && max && check_mqh(thd,user,thd->host,max)) - return -1; mysql_log.write(thd,command, (thd->priv_user == thd->user ? (char*) "%s@%s on %s" : @@ -269,8 +190,11 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, thd->host_or_ip, db ? db : (char*) ""); thd->db_access=0; + /* Don't allow user to connect if he has done too many queries */ + if (max_questions && check_mqh(thd,user,thd->host_or_ip,max_questions)) + return -1; if (max_user_connections && - check_for_max_user_connections(user, thd->host, max)) + check_for_max_user_connections(user, thd->host, max_questions)) return -1; if (db && db[0]) { @@ -285,30 +209,40 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, } /* -** check for maximum allowable user connections -** if mysql server is started with corresponding -** variable that is greater then 0 + Check for maximum allowable user connections, if the mysqld server is + started with corresponding variable that is greater then 0. */ +static byte* get_key_conn(user_conn *buff, uint *length, + my_bool not_used __attribute__((unused))) +{ + *length=buff->len; + return (byte*) buff->user; +} + +static void free_user(struct user_conn *uc) +{ + my_free((char*) uc,MYF(0)); +} + void init_max_user_conn(void) { - (void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0, + (void) hash_init(&hash_user_connections,max_connections,0,0, (hash_get_key) get_key_conn, (void (*)(void*)) free_user, 0); } -static int check_for_max_user_connections(const char *user, const char *host, uint max) +static int check_for_max_user_connections(const char *user, const char *host, + uint max_questions) { int error=1; uint temp_len; char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2]; struct user_conn *uc; - if (!user) - user=""; - if (!host) - host=""; DBUG_ENTER("check_for_max_user_connections"); + DBUG_ASSERT(user != 0); + DBUG_ASSERT(host != 0); DBUG_PRINT("enter",("user: '%s' host: '%s'", user, host)); temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host, @@ -341,7 +275,7 @@ static int check_for_max_user_connections(const char *user, const char *host, ui uc->len = temp_len; uc->connections = 1; uc->questions=0; - uc->max=max; + uc->max_questions=max_questions; uc->intime=current_thd->thr_create_time; if (hash_insert(&hash_user_connections, (byte*) uc)) { @@ -397,9 +331,82 @@ void free_max_user_conn(void) hash_free(&hash_user_connections); } + /* -** check connnetion and get priviliges -** returns 0 on ok, -1 < if error is given > 0 on error. + Check if maximum queries per hour limit has been reached + returns 0 if OK. +*/ + +static bool check_mqh(THD *thd, const char *user, const char *host, + uint max_questions) +{ + uint temp_len; + char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2]; + struct user_conn *uc; + bool error=0; + + DBUG_ASSERT(user != 0); + DBUG_ASSERT(host != 0); + + /* TODO: Add username + host to THD for faster execution */ + temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user)-1, user, "@", host, + NullS) - temp_user); + (void) pthread_mutex_lock(&LOCK_user_conn); + uc = (struct user_conn *) hash_search(&hash_user_connections, + (byte*) temp_user, temp_len); + if (uc) + { + /* user found ; check for no. of queries */ + bool my_start = thd->start_time != 0; + time_t check_time = (my_start) ? thd->start_time : time(NULL); + if (check_time - uc->intime >= 3600) + { + uc->questions=(uint) my_start; + uc->intime=check_time; + } + else if (uc->max_questions && ++(uc->questions) > uc->max_questions) + { + net_printf(&thd->net, ER_USER_LIMIT_REACHED, temp_user, "max_questions", + (long) uc->questions); + error=1; + goto end; + } + } + else + { + struct user_conn *uc= ((struct user_conn*) + my_malloc(sizeof(struct user_conn) + temp_len+1, + MYF(MY_WME))); + if (!uc) + { + send_error(¤t_thd->net, 0, NullS); // Out of memory + error=1; + goto end; + } + uc->user=(char*) (uc+1); + memcpy(uc->user,temp_user,temp_len+1); + uc->len = temp_len; + uc->connections = 1; + uc->questions=0; + uc->max_questions=max_questions; + uc->intime=current_thd->thr_create_time; + if (hash_insert(&hash_user_connections, (byte*) uc)) + { + my_free((char*) uc,0); + send_error(¤t_thd->net, 0, NullS); // Out of memory + error=1; + } + } + +end: + (void) pthread_mutex_unlock(&LOCK_user_conn); + return error; +} + + +/* + Check connnetion and get priviliges + Returns 0 on ok, -1 < if error is given > 0 on error. */ @@ -408,9 +415,7 @@ check_connections(THD *thd) { uint connect_errors=0; NET *net= &thd->net; - /* - ** store the connection details - */ + /* Store the connection details */ DBUG_PRINT("info", (("check_connections called by thread %d"), thd->thread_id)); DBUG_PRINT("info",("New connection received on %s", diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index e4a277d1434..2c4c6216ab7 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -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, diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 146490c7b87..0b408920703 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -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; } - - diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 94018e0046a..89082b40d87 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -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; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8629930cf5c..131266a11d6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -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 */ diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 5776cba7e96..6c868b542d1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -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; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 32a87f194ac..91cf0ae5fc9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -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: diff --git a/strings/str2int.c b/strings/str2int.c index f5a7fed8a4a..58669287473 100644 --- a/strings/str2int.c +++ b/strings/str2int.c @@ -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 */ |
