Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
2e009645
Commit
2e009645
authored
Jan 26, 2002
by
unknown
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
48ff048f
845db7c2
Changes
17
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
891 additions
and
266 deletions
+891
-266
BitKeeper/etc/logging_ok
BitKeeper/etc/logging_ok
+1
-0
Docs/manual.texi
Docs/manual.texi
+21
-21
client/mysqltest.c
client/mysqltest.c
+51
-6
include/Makefile.am
include/Makefile.am
+1
-1
include/my_getopt.h
include/my_getopt.h
+46
-0
include/my_sys.h
include/my_sys.h
+4
-1
myisam/myisamchk.c
myisam/myisamchk.c
+220
-184
mysql-test/r/rpl000016.result
mysql-test/r/rpl000016.result
+1
-2
mysql-test/t/rpl000016.test
mysql-test/t/rpl000016.test
+1
-3
mysys/Makefile.am
mysys/Makefile.am
+1
-1
mysys/getvar.c
mysys/getvar.c
+76
-1
mysys/mf_iocache.c
mysys/mf_iocache.c
+19
-3
mysys/my_getopt.c
mysys/my_getopt.c
+313
-0
sql/log.cc
sql/log.cc
+25
-0
sql/log_event.cc
sql/log_event.cc
+38
-26
sql/slave.cc
sql/slave.cc
+72
-17
sql/sql_class.h
sql/sql_class.h
+1
-0
No files found.
BitKeeper/etc/logging_ok
View file @
2e009645
...
@@ -42,3 +42,4 @@ bell@sanja.is.com.ua
...
@@ -42,3 +42,4 @@ bell@sanja.is.com.ua
kaj@work.mysql.com
kaj@work.mysql.com
mwagner@cash.mwagner.org
mwagner@cash.mwagner.org
tom@basil-firewall.home.com
tom@basil-firewall.home.com
jani@rhols221.adsl.netsonic.fi
Docs/manual.texi
View file @
2e009645
...
@@ -48290,13 +48290,13 @@ Fixed bug in multi table delete.
...
@@ -48290,13 +48290,13 @@ Fixed bug in multi table delete.
Fixed bug in @code{SELECT CONCAT(argument-list) ... GROUP BY 1}.
Fixed bug in @code{SELECT CONCAT(argument-list) ... GROUP BY 1}.
@item
@item
@code{SELECT .. INSERT} did a full rollback in case of an error. Fixed
@code{SELECT .. INSERT} did a full rollback in case of an error. Fixed
so that we only rollback the last statement.
so that we only roll
back the last statement.
@item
@item
Fixed bug with empty expression for boolean fulltext search.
Fixed bug with empty expression for boolean fulltext search.
@item
@item
Fixed core dump bug in updating fulltext key from/to @code{NULL}.
Fixed core dump bug in updating fulltext key from/to @code{NULL}.
@item
@item
ODBC compatibility: Added @code{BIT_LENGTH()}
ODBC compatibility: Added @code{BIT_LENGTH()}
.
@item
@item
Fixed core dump bug in @code{GROUP BY BINARY column}.
Fixed core dump bug in @code{GROUP BY BINARY column}.
@item
@item
...
@@ -48315,7 +48315,7 @@ For more information, read @ref{Cast Functions}.
...
@@ -48315,7 +48315,7 @@ For more information, read @ref{Cast Functions}.
@code{CREATE ... SELECT} on @code{DATE} and @code{TIME} functions now
@code{CREATE ... SELECT} on @code{DATE} and @code{TIME} functions now
create columns of the expected type.
create columns of the expected type.
@item
@item
Changed order
of how
keys are created in tables.
Changed order
in which
keys are created in tables.
@item
@item
Added a new columns @code{Null} and @code{Index_type} to @code{SHOW INDEX}.
Added a new columns @code{Null} and @code{Index_type} to @code{SHOW INDEX}.
@end itemize
@end itemize
...
@@ -48330,17 +48330,17 @@ Fixed bug when @code{HANDLER} was used with some unsupported table type.
...
@@ -48330,17 +48330,17 @@ Fixed bug when @code{HANDLER} was used with some unsupported table type.
@code{mysqldump} now puts @code{ALTER TABLE table_name DISABLE KEYS} and
@code{mysqldump} now puts @code{ALTER TABLE table_name DISABLE KEYS} and
@code{ALTER TABLE table_name DISABLE KEYS} in the sql dump.
@code{ALTER TABLE table_name DISABLE KEYS} in the sql dump.
@item
@item
Added @code{mysql_fix_extensions} script
Added @code{mysql_fix_extensions} script
.
@item
@item
Fixed stack overrun problem @code{LOAD DATA FROM MASTER} on OSF1.
Fixed stack overrun problem @code{LOAD DATA FROM MASTER} on OSF1.
@item
@item
Fixed shutdown problem on HPUX.
Fixed shutdown problem on HP
-
UX.
@item
@item
Added functions @code{des_encrypt()} and @code{des_decrypt()}.
Added functions @code{des_encrypt()} and @code{des_decrypt()}.
@item
@item
Added statement @code{FLUSH DES_KEY_FILE}.
Added statement @code{FLUSH DES_KEY_FILE}.
@item
@item
Added
mysqld
option @code{--des-key-file}.
Added
@code{mysqld}
option @code{--des-key-file}.
@item
@item
@code{HEX(string)} now returns the characters in string converted to
@code{HEX(string)} now returns the characters in string converted to
hexadecimal.
hexadecimal.
...
@@ -48352,7 +48352,7 @@ Changed @code{SELECT ... IN SHARE MODE} to
...
@@ -48352,7 +48352,7 @@ Changed @code{SELECT ... IN SHARE MODE} to
@item
@item
A new query cache to cache results from identical @code{SELECT} queries.
A new query cache to cache results from identical @code{SELECT} queries.
@item
@item
Fixed core dump bug on 64
bit machines when it got a wrong
communication
Fixed core dump bug on 64
-bit machines when it got an incorrect
communication
packet.
packet.
@item
@item
@code{MATCH ... AGAINST(... IN BOOLEAN MODE)} can now work
@code{MATCH ... AGAINST(... IN BOOLEAN MODE)} can now work
...
@@ -48370,7 +48370,7 @@ of @code{FULLTEXT} indexes.
...
@@ -48370,7 +48370,7 @@ of @code{FULLTEXT} indexes.
Fixed bug in @code{DELETE ... WHERE ... MATCH ...}.
Fixed bug in @code{DELETE ... WHERE ... MATCH ...}.
@item
@item
Added support for @code{MATCH ... AGAINST(... IN BOOLEAN MODE)}.
Added support for @code{MATCH ... AGAINST(... IN BOOLEAN MODE)}.
@strong{Note: you
have to
rebuild your tables with
@strong{Note: you
must
rebuild your tables with
@code{ALTER TABLE tablename TYPE=MyISAM} to be
@code{ALTER TABLE tablename TYPE=MyISAM} to be
able to use boolean fulltext search}.
able to use boolean fulltext search}.
@item
@item
...
@@ -48391,7 +48391,7 @@ Added boolean fulltext search code. It should be considered early alpha.
...
@@ -48391,7 +48391,7 @@ Added boolean fulltext search code. It should be considered early alpha.
Extended @code{MODIFY} and @code{CHANGE} in @code{ALTER TABLE} to accept
Extended @code{MODIFY} and @code{CHANGE} in @code{ALTER TABLE} to accept
the @code{AFTER} keyword.
the @code{AFTER} keyword.
@item
@item
Index are now used with @code{ORDER BY} on a whole @code{InnoDB} table.
Index
es
are now used with @code{ORDER BY} on a whole @code{InnoDB} table.
@end itemize
@end itemize
@node News-4.0.0, , News-4.0.1, News-4.0.x
@node News-4.0.0, , News-4.0.1, News-4.0.x
...
@@ -48446,28 +48446,28 @@ Speed up all internal list handling.
...
@@ -48446,28 +48446,28 @@ Speed up all internal list handling.
@item
@item
Speed up @code{IS NULL}, @code{ISNULL()} and some other internal primitives.
Speed up @code{IS NULL}, @code{ISNULL()} and some other internal primitives.
@item
@item
Creating full text indexes are now
much faster.
Full text index creation now is
much faster.
@item
@item
Tree-like cache to speed up bulk inserts and
Tree-like cache to speed up bulk inserts and
@code{myisam_bulk_insert_tree_size} variable.
@code{myisam_bulk_insert_tree_size} variable.
@item
@item
Searching on packed (@code{CHAR}/@code{VARCHAR}) keys
are
now much faster.
Searching on packed (@code{CHAR}/@code{VARCHAR}) keys
is
now much faster.
@item
@item
Optimised queries of type:
Optimised queries of type:
@code{SELECT DISTINCT * from table_name ORDER by key_part1 LIMIT #}
@code{SELECT DISTINCT * from table_name ORDER by key_part1 LIMIT #}
.
@item
@item
@code{SHOW CREATE TABLE} now shows all table attributes.
@code{SHOW CREATE TABLE} now shows all table attributes.
@item
@item
@code{ORDER BY ... DESC} can now use keys.
@code{ORDER BY ... DESC} can now use keys.
@item
@item
@code{LOAD DATA FROM MASTER}
"auto-magically"
sets up a slave.
@code{LOAD DATA FROM MASTER}
``auto-magically''
sets up a slave.
@item
@item
Renamed @code{safe_mysqld} to @code{mysqld_safe}.
Renamed @code{safe_mysqld} to @code{mysqld_safe}.
@item
@item
Added support for symbolic links to @code{MyISAM} tables. Symlink handling is
Added support for symbolic links to @code{MyISAM} tables. Symlink handling is
now enabled by default for Windows.
now enabled by default for Windows.
@item
@item
@code{LOAD DATA FROM MASTER}
"auto-magically"
sets up a slave.
@code{LOAD DATA FROM MASTER}
``auto-magically''
sets up a slave.
@item
@item
Added @code{SQL_CALC_FOUND_ROWS} and @code{FOUND_ROWS()}. This makes it
Added @code{SQL_CALC_FOUND_ROWS} and @code{FOUND_ROWS()}. This makes it
possible to know how many rows a query would have returned
possible to know how many rows a query would have returned
...
@@ -48486,15 +48486,15 @@ Added @code{ORDER BY} syntax to @code{UPDATE} and @code{DELETE}.
...
@@ -48486,15 +48486,15 @@ Added @code{ORDER BY} syntax to @code{UPDATE} and @code{DELETE}.
Added @code{ALTER TABLE table_name DISABLE KEYS} and
Added @code{ALTER TABLE table_name DISABLE KEYS} and
@code{ALTER TABLE table_name ENABLE KEYS} commands.
@code{ALTER TABLE table_name ENABLE KEYS} commands.
@item
@item
Allow
one to use @code{IN} instead of
@code{FROM} in @code{SHOW} commands.
Allow
use of @code{IN} as a synonym for
@code{FROM} in @code{SHOW} commands.
@item
@item
Implemented ``repair by sort'' for @code{FULLTEXT} indexes.
Implemented ``repair by sort'' for @code{FULLTEXT} indexes.
@code{REPAIR TABLE}, @code{ALTER TABLE}, and @code{OPTIMIZE TABLE}
@code{REPAIR TABLE}, @code{ALTER TABLE}, and @code{OPTIMIZE TABLE}
for tables with @code{FULLTEXT} indexes are now up to 100 times faster.
for tables with @code{FULLTEXT} indexes are now up to 100 times faster.
@item
@item
Allow ANSI SQL syntax @code{X'hexadecimal-number'}
Allow ANSI SQL syntax @code{X'hexadecimal-number'}
.
@item
@item
Cleaned up global lock handling for @code{FLUSH TABLES WITH READ LOCK}
Cleaned up global lock handling for @code{FLUSH TABLES WITH READ LOCK}
.
@item
@item
Fixed problem with @code{DATETIME = constant} in @code{WHERE} optimisation.
Fixed problem with @code{DATETIME = constant} in @code{WHERE} optimisation.
@item
@item
...
@@ -48610,13 +48610,13 @@ Restrict InnoDB keys to 500 bytes.
...
@@ -48610,13 +48610,13 @@ Restrict InnoDB keys to 500 bytes.
@item
@item
InnoDB now supports @code{NULL} in keys.
InnoDB now supports @code{NULL} in keys.
@item
@item
Fixed shutdown problem on HPUX. (Introduced in 3.23.46)
Fixed shutdown problem on HP
-
UX. (Introduced in 3.23.46)
@item
@item
Fixed core-dump bug in replication when using
SELECT RELEASE_LOCK();
Fixed core-dump bug in replication when using
@code{SELECT RELEASE_LOCK()}.
@item
@item
Added new command: @code{DO expression,[expression]}
Added new command: @code{DO expression,[expression]}
@item
@item
Added @code{slave-skip-errors} option
Added @code{slave-skip-errors} option
.
@item
@item
Added statistics variables for all MySQL commands. (@code{SHOW STATUS} is
Added statistics variables for all MySQL commands. (@code{SHOW STATUS} is
now much longer).
now much longer).
...
@@ -48627,7 +48627,7 @@ Fixed that @code{GROUP BY expr DESC} works.
...
@@ -48627,7 +48627,7 @@ Fixed that @code{GROUP BY expr DESC} works.
@item
@item
Fixed bug when using @code{t1 LEFT JOIN t2 ON t2.key=constant}.
Fixed bug when using @code{t1 LEFT JOIN t2 ON t2.key=constant}.
@item
@item
@code{mysql_config} now also work with binary (relocated) distributions.
@code{mysql_config} now also work
s
with binary (relocated) distributions.
@end itemize
@end itemize
@node News-3.23.46, News-3.23.45, News-3.23.47, News-3.23.x
@node News-3.23.46, News-3.23.45, News-3.23.47, News-3.23.x
client/mysqltest.c
View file @
2e009645
...
@@ -15,7 +15,8 @@
...
@@ -15,7 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* mysqltest test tool
/* mysqltest test tool
* See man page for more information.
* See the manual for more information
* TODO: document better how mysqltest works
*
*
* Written by:
* Written by:
* Sasha Pachev <sasha@mysql.com>
* Sasha Pachev <sasha@mysql.com>
...
@@ -26,9 +27,6 @@
...
@@ -26,9 +27,6 @@
/**********************************************************************
/**********************************************************************
TODO:
TODO:
- Print also the queries that returns a result to the log file; This makes
it much easier to find out what's wrong.
- Do comparison line by line, instead of doing a full comparison of
- Do comparison line by line, instead of doing a full comparison of
the text file. This will save space as we don't need to keep many
the text file. This will save space as we don't need to keep many
results in memory. It will also make it possible to do simple
results in memory. It will also make it possible to do simple
...
@@ -43,7 +41,7 @@
...
@@ -43,7 +41,7 @@
**********************************************************************/
**********************************************************************/
#define MTEST_VERSION "1.1
3
"
#define MTEST_VERSION "1.1
4
"
#include <my_global.h>
#include <my_global.h>
#include <mysql_embed.h>
#include <mysql_embed.h>
...
@@ -88,6 +86,12 @@
...
@@ -88,6 +86,12 @@
#define CON_RETRY_SLEEP 2
#define CON_RETRY_SLEEP 2
#define MAX_CON_TRIES 5
#define MAX_CON_TRIES 5
#ifndef OS2
#define SLAVE_POLL_INTERVAL 300000
/* 0.3 of a sec */
#else
#defile SLAVE_POLL_INTERVAL 0.3
#endif
enum
{
OPT_MANAGER_USER
=
256
,
OPT_MANAGER_HOST
,
OPT_MANAGER_PASSWD
,
enum
{
OPT_MANAGER_USER
=
256
,
OPT_MANAGER_HOST
,
OPT_MANAGER_PASSWD
,
OPT_MANAGER_PORT
,
OPT_MANAGER_WAIT_TIMEOUT
};
OPT_MANAGER_PORT
,
OPT_MANAGER_WAIT_TIMEOUT
};
...
@@ -187,6 +191,7 @@ Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
...
@@ -187,6 +191,7 @@ Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT,
Q_ENABLE_QUERY_LOG
,
Q_DISABLE_QUERY_LOG
,
Q_ENABLE_QUERY_LOG
,
Q_DISABLE_QUERY_LOG
,
Q_ENABLE_RESULT_LOG
,
Q_DISABLE_RESULT_LOG
,
Q_ENABLE_RESULT_LOG
,
Q_DISABLE_RESULT_LOG
,
Q_SERVER_START
,
Q_SERVER_STOP
,
Q_REQUIRE_MANAGER
,
Q_SERVER_START
,
Q_SERVER_STOP
,
Q_REQUIRE_MANAGER
,
Q_WAIT_FOR_SLAVE_TO_STOP
,
Q_UNKNOWN
,
/* Unknown command. */
Q_UNKNOWN
,
/* Unknown command. */
Q_COMMENT
,
/* Comments, ignored. */
Q_COMMENT
,
/* Comments, ignored. */
Q_COMMENT_WITH_COMMAND
Q_COMMENT_WITH_COMMAND
...
@@ -222,7 +227,7 @@ const char *command_names[] = {
...
@@ -222,7 +227,7 @@ const char *command_names[] = {
"enable_query_log"
,
"disable_query_log"
,
"enable_query_log"
,
"disable_query_log"
,
"enable_result_log"
,
"disable_result_log"
,
"enable_result_log"
,
"disable_result_log"
,
"server_start"
,
"server_stop"
,
"server_start"
,
"server_stop"
,
"require_manager"
,
"require_manager"
,
"wait_for_slave_to_stop"
,
0
0
};
};
...
@@ -653,6 +658,45 @@ int open_file(const char* name)
...
@@ -653,6 +658,45 @@ int open_file(const char* name)
return
0
;
return
0
;
}
}
/* ugly long name, but we are following the convention */
int
do_wait_for_slave_to_stop
(
struct
st_query
*
__attribute__
((
unused
))
q
)
{
MYSQL
*
mysql
=
&
cur_con
->
mysql
;
#ifndef OS2
struct
timeval
t
;
#endif
for
(;;)
{
MYSQL_RES
*
res
;
MYSQL_ROW
row
;
int
done
;
LINT_INIT
(
res
);
if
(
mysql_query
(
mysql
,
"show status like 'Slave_running'"
)
||
!
(
res
=
mysql_store_result
(
mysql
)))
die
(
"Query failed while probing slave for stop: %s"
,
mysql_error
(
mysql
));
if
(
!
(
row
=
mysql_fetch_row
(
res
))
||
!
row
[
1
])
{
mysql_free_result
(
res
);
die
(
"Strange result from query while probing slave for stop"
);
}
done
=
!
strcmp
(
row
[
1
],
"OFF"
);
mysql_free_result
(
res
);
if
(
done
)
break
;
#ifndef OS2
t
.
tv_sec
=
0
;
t
.
tv_usec
=
SLAVE_POLL_INTERVAL
;
select
(
0
,
0
,
0
,
0
,
&
t
);
/* sleep */
#else
DosSleep
(
OS2_SLAVE_POLL_INTERVAL
);
#endif
}
return
0
;
}
int
do_require_manager
(
struct
st_query
*
__attribute__
((
unused
))
q
)
int
do_require_manager
(
struct
st_query
*
__attribute__
((
unused
))
q
)
{
{
if
(
!
manager
)
if
(
!
manager
)
...
@@ -2335,6 +2379,7 @@ int main(int argc, char** argv)
...
@@ -2335,6 +2379,7 @@ int main(int argc, char** argv)
case
Q_DISABLE_RESULT_LOG
:
disable_result_log
=
1
;
break
;
case
Q_DISABLE_RESULT_LOG
:
disable_result_log
=
1
;
break
;
case
Q_SOURCE
:
do_source
(
q
);
break
;
case
Q_SOURCE
:
do_source
(
q
);
break
;
case
Q_SLEEP
:
do_sleep
(
q
);
break
;
case
Q_SLEEP
:
do_sleep
(
q
);
break
;
case
Q_WAIT_FOR_SLAVE_TO_STOP
:
do_wait_for_slave_to_stop
(
q
);
break
;
case
Q_REQUIRE_MANAGER
:
do_require_manager
(
q
);
break
;
case
Q_REQUIRE_MANAGER
:
do_require_manager
(
q
);
break
;
#ifndef EMBEDDED_LIBRARY
#ifndef EMBEDDED_LIBRARY
case
Q_SERVER_START
:
do_server_start
(
q
);
break
;
case
Q_SERVER_START
:
do_server_start
(
q
);
break
;
...
...
include/Makefile.am
View file @
2e009645
...
@@ -28,7 +28,7 @@ noinst_HEADERS = config-win.h \
...
@@ -28,7 +28,7 @@ noinst_HEADERS = config-win.h \
my_dir.h mysys_err.h my_base.h
\
my_dir.h mysys_err.h my_base.h
\
my_nosys.h my_alarm.h queues.h
\
my_nosys.h my_alarm.h queues.h
\
my_tree.h hash.h thr_alarm.h thr_lock.h
\
my_tree.h hash.h thr_alarm.h thr_lock.h
\
getopt.h t_ctype.h violite.h md5.h
\
getopt.h
my_getopt.h
t_ctype.h violite.h md5.h
\
mysql_version.h.in
mysql_version.h.in
# mysql_version.h are generated
# mysql_version.h are generated
...
...
include/my_getopt.h
0 → 100644
View file @
2e009645
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
struct
my_optarg
{
char
*
arg
;
/* option argument */
int
pos
;
/* next element in ARGV */
int
verbose
;
/* 0 = inhibit warnings of unrecognized options */
int
unrecognized
;
/* position of the unrecognized option */
};
enum
get_opt_var_type
{
GET_NO_ARG
,
GET_INT
,
GET_LL
,
GET_STR
};
enum
get_opt_arg_type
{
NO_ARG
,
OPT_ARG
,
REQUIRED_ARG
};
struct
my_option
{
const
char
*
name
;
/* Name of the option */
const
char
*
comment
;
/* option comment, for autom. --help */
char
*
value
;
/* The variable value */
const
char
**
str_values
;
/* Pointer to possible values */
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 */
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 */
};
include/my_sys.h
View file @
2e009645
...
@@ -643,7 +643,10 @@ extern int _my_b_write(IO_CACHE *info,const byte *Buffer,uint Count);
...
@@ -643,7 +643,10 @@ extern int _my_b_write(IO_CACHE *info,const byte *Buffer,uint Count);
extern
int
my_b_append
(
IO_CACHE
*
info
,
const
byte
*
Buffer
,
uint
Count
);
extern
int
my_b_append
(
IO_CACHE
*
info
,
const
byte
*
Buffer
,
uint
Count
);
extern
int
my_block_write
(
IO_CACHE
*
info
,
const
byte
*
Buffer
,
extern
int
my_block_write
(
IO_CACHE
*
info
,
const
byte
*
Buffer
,
uint
Count
,
my_off_t
pos
);
uint
Count
,
my_off_t
pos
);
extern
int
flush_io_cache
(
IO_CACHE
*
info
);
extern
int
_flush_io_cache
(
IO_CACHE
*
info
,
int
need_append_buffer_lock
);
#define flush_io_cache(info) _flush_io_cache((info),1)
extern
int
end_io_cache
(
IO_CACHE
*
info
);
extern
int
end_io_cache
(
IO_CACHE
*
info
);
extern
uint
my_b_fill
(
IO_CACHE
*
info
);
extern
uint
my_b_fill
(
IO_CACHE
*
info
);
extern
void
my_b_seek
(
IO_CACHE
*
info
,
my_off_t
pos
);
extern
void
my_b_seek
(
IO_CACHE
*
info
,
my_off_t
pos
);
...
...
myisam/myisamchk.c
View file @
2e009645
This diff is collapsed.
Click to expand it.
mysql-test/r/rpl000016.result
View file @
2e009645
...
@@ -33,7 +33,6 @@ master-bin.003
...
@@ -33,7 +33,6 @@ master-bin.003
insert into t2 values(1234);
insert into t2 values(1234);
set insert_id=1234;
set insert_id=1234;
insert into t2 values(NULL);
insert into t2 values(NULL);
slave stop;
set sql_slave_skip_counter=1;
set sql_slave_skip_counter=1;
slave start;
slave start;
purge master logs to 'master-bin.003';
purge master logs to 'master-bin.003';
...
@@ -66,7 +65,7 @@ slave stop;
...
@@ -66,7 +65,7 @@ slave stop;
slave start;
slave start;
show slave status;
show slave status;
Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos
Master_Host Master_User Master_Port Connect_retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Exec_master_log_pos
127.0.0.1 root MASTER_PORT 60 master-bin.006 445 mysql-relay-bin.004 13
12
master-bin.006 Yes Yes 0 0 445
127.0.0.1 root MASTER_PORT 60 master-bin.006 445 mysql-relay-bin.004 13
76
master-bin.006 Yes Yes 0 0 445
lock tables t3 read;
lock tables t3 read;
select count(*) from t3 where n >= 4;
select count(*) from t3 where n >= 4;
count(*)
count(*)
...
...
mysql-test/t/rpl000016.test
View file @
2e009645
...
@@ -51,9 +51,7 @@ insert into t2 values(NULL);
...
@@ -51,9 +51,7 @@ insert into t2 values(NULL);
connection
slave
;
connection
slave
;
sync_with_master
;
sync_with_master
;
#the slave may have already stopped, so we ignore the error
wait_for_slave_to_stop
;
--
error
0
,
1199
!
slave
stop
;
#restart slave skipping one event
#restart slave skipping one event
set
sql_slave_skip_counter
=
1
;
set
sql_slave_skip_counter
=
1
;
...
...
mysys/Makefile.am
View file @
2e009645
...
@@ -44,7 +44,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
...
@@ -44,7 +44,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\
my_delete.c my_rename.c my_redel.c my_tempnam.c
\
my_delete.c my_rename.c my_redel.c my_tempnam.c
\
my_chsize.c my_lread.c my_lwrite.c my_clock.c
\
my_chsize.c my_lread.c my_lwrite.c my_clock.c
\
my_quick.c my_lockmem.c my_static.c
\
my_quick.c my_lockmem.c my_static.c
\
getopt.c getopt1.c getvar.c my_mkdir.c
\
getopt.c getopt1.c
my_getopt.c
getvar.c my_mkdir.c
\
default.c my_compress.c checksum.c raid.cc my_net.c
\
default.c my_compress.c checksum.c raid.cc my_net.c
\
my_vsnprintf.c charset.c my_bitmap.c my_bit.c md5.c
my_vsnprintf.c charset.c my_bitmap.c my_bit.c md5.c
EXTRA_DIST
=
thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c
\
EXTRA_DIST
=
thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c
\
...
...
mysys/getvar.c
View file @
2e009645
...
@@ -19,7 +19,7 @@
...
@@ -19,7 +19,7 @@
#include "mysys_priv.h"
#include "mysys_priv.h"
#include <m_string.h>
#include <m_string.h>
#include <m_ctype.h>
#include <m_ctype.h>
#include <my_getopt.h>
/* set all changeable variables */
/* set all changeable variables */
void
set_all_changeable_vars
(
CHANGEABLE_VAR
*
vars
)
void
set_all_changeable_vars
(
CHANGEABLE_VAR
*
vars
)
...
@@ -109,3 +109,78 @@ my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars)
...
@@ -109,3 +109,78 @@ my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars)
}
}
DBUG_RETURN
(
1
);
DBUG_RETURN
(
1
);
}
}
my_bool
my_set_changeable_var
(
my_string
str
,
const
struct
my_option
*
vars
)
{
char
endchar
;
my_string
end
;
DBUG_ENTER
(
"my_set_changeable_var"
);
DBUG_PRINT
(
"enter"
,(
"%s"
,
str
));
if
(
str
)
{
if
(
!
(
end
=
strchr
(
str
,
'='
)))
fprintf
(
stderr
,
"Can't find '=' in expression '%s' to option -O
\n
"
,
str
);
else
{
uint
length
,
found_count
=
0
;
const
struct
my_option
*
var
,
*
found
;
my_string
var_end
;
const
char
*
name
;
longlong
num
;
/* Skip end space from variable */
for
(
var_end
=
end
;
end
>
str
&&
isspace
(
var_end
[
-
1
])
;
var_end
--
)
;
length
=
(
uint
)
(
var_end
-
str
);
/* Skip start space from argument */
for
(
end
++
;
isspace
(
*
end
)
;
end
++
)
;
for
(
var
=
vars
,
found
=
0
;
(
name
=
var
->
name
);
var
++
)
{
if
(
var
->
changeable_var
)
{
if
(
!
my_casecmp
(
name
,
str
,
length
))
{
found
=
var
;
found_count
++
;
if
(
!
name
[
length
])
{
found_count
=
1
;
break
;
}
}
}
}
if
(
found_count
==
0
)
{
fprintf
(
stderr
,
"No variable match for: -O '%s'
\n
"
,
str
);
DBUG_RETURN
(
1
);
}
if
(
found_count
>
1
)
{
fprintf
(
stderr
,
"Variable prefix '%*s' is not unique
\n
"
,
length
,
str
);
DBUG_RETURN
(
1
);
}
num
=
strtoll
(
end
,
(
char
**
)
NULL
,
10
);
endchar
=
strend
(
end
)[
-
1
];
if
(
endchar
==
'k'
||
endchar
==
'K'
)
num
*=
1024
;
else
if
(
endchar
==
'm'
||
endchar
==
'M'
)
num
*=
1024L
*
1024L
;
else
if
(
endchar
==
'g'
||
endchar
==
'G'
)
num
*=
1024L
*
1024L
*
1024L
;
else
if
(
!
isdigit
(
endchar
))
{
fprintf
(
stderr
,
"Unknown prefix used for variable value '%s'
\n
"
,
str
);
DBUG_RETURN
(
1
);
}
if
(
num
<
(
longlong
)
found
->
min_value
)
num
=
(
longlong
)
found
->
min_value
;
else
if
(
num
>
0
&&
(
ulonglong
)
num
>
(
ulonglong
)
(
ulong
)
found
->
max_value
)
num
=
(
longlong
)
(
ulong
)
found
->
max_value
;
num
=
((
num
-
(
longlong
)
found
->
sub_size
)
/
(
ulonglong
)
found
->
block_size
);
/* (*found->varptr)= (long) (num*(ulonglong) found->block_size);*/
DBUG_RETURN
(
0
);
}
}
DBUG_RETURN
(
1
);
}
mysys/mf_iocache.c
View file @
2e009645
...
@@ -808,13 +808,19 @@ int my_b_append(register IO_CACHE *info, const byte *Buffer, uint Count)
...
@@ -808,13 +808,19 @@ int my_b_append(register IO_CACHE *info, const byte *Buffer, uint Count)
Buffer
+=
rest_length
;
Buffer
+=
rest_length
;
Count
-=
rest_length
;
Count
-=
rest_length
;
info
->
write_pos
+=
rest_length
;
info
->
write_pos
+=
rest_length
;
if
(
flush_io_cache
(
info
))
if
(
_flush_io_cache
(
info
,
0
))
{
unlock_append_buffer
(
info
);
return
1
;
return
1
;
}
if
(
Count
>=
IO_SIZE
)
if
(
Count
>=
IO_SIZE
)
{
/* Fill first intern buffer */
{
/* Fill first intern buffer */
length
=
Count
&
(
uint
)
~
(
IO_SIZE
-
1
);
length
=
Count
&
(
uint
)
~
(
IO_SIZE
-
1
);
if
(
my_write
(
info
->
file
,
Buffer
,(
uint
)
length
,
info
->
myflags
|
MY_NABP
))
if
(
my_write
(
info
->
file
,
Buffer
,(
uint
)
length
,
info
->
myflags
|
MY_NABP
))
{
unlock_append_buffer
(
info
);
return
info
->
error
=
-
1
;
return
info
->
error
=
-
1
;
}
Count
-=
length
;
Count
-=
length
;
Buffer
+=
length
;
Buffer
+=
length
;
}
}
...
@@ -883,14 +889,16 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
...
@@ -883,14 +889,16 @@ int my_block_write(register IO_CACHE *info, const byte *Buffer, uint Count,
/* Flush write cache */
/* Flush write cache */
int
flush_io_cache
(
IO_CACHE
*
info
)
int
_flush_io_cache
(
IO_CACHE
*
info
,
int
need_append_buffer_lock
)
{
{
uint
length
;
uint
length
;
my_bool
append_cache
;
my_bool
append_cache
;
my_off_t
pos_in_file
;
my_off_t
pos_in_file
;
DBUG_ENTER
(
"flush_io_cache"
);
DBUG_ENTER
(
"flush_io_cache"
);
append_cache
=
(
info
->
type
==
SEQ_READ_APPEND
);
if
(
!
(
append_cache
=
(
info
->
type
==
SEQ_READ_APPEND
)))
need_append_buffer_lock
=
0
;
if
(
info
->
type
==
WRITE_CACHE
||
append_cache
)
if
(
info
->
type
==
WRITE_CACHE
||
append_cache
)
{
{
if
(
info
->
file
==
-
1
)
if
(
info
->
file
==
-
1
)
...
@@ -898,6 +906,8 @@ int flush_io_cache(IO_CACHE *info)
...
@@ -898,6 +906,8 @@ int flush_io_cache(IO_CACHE *info)
if
(
real_open_cached_file
(
info
))
if
(
real_open_cached_file
(
info
))
DBUG_RETURN
((
info
->
error
=
-
1
));
DBUG_RETURN
((
info
->
error
=
-
1
));
}
}
if
(
need_append_buffer_lock
)
lock_append_buffer
(
info
);
if
((
length
=
(
uint
)
(
info
->
write_pos
-
info
->
write_buffer
)))
if
((
length
=
(
uint
)
(
info
->
write_pos
-
info
->
write_buffer
)))
{
{
pos_in_file
=
info
->
pos_in_file
;
pos_in_file
=
info
->
pos_in_file
;
...
@@ -909,6 +919,8 @@ int flush_io_cache(IO_CACHE *info)
...
@@ -909,6 +919,8 @@ int flush_io_cache(IO_CACHE *info)
if
(
my_seek
(
info
->
file
,
pos_in_file
,
MY_SEEK_SET
,
MYF
(
0
))
==
if
(
my_seek
(
info
->
file
,
pos_in_file
,
MY_SEEK_SET
,
MYF
(
0
))
==
MY_FILEPOS_ERROR
)
MY_FILEPOS_ERROR
)
{
{
if
(
need_append_buffer_lock
)
unlock_append_buffer
(
info
);
DBUG_RETURN
((
info
->
error
=
-
1
));
DBUG_RETURN
((
info
->
error
=
-
1
));
}
}
if
(
!
append_cache
)
if
(
!
append_cache
)
...
@@ -932,6 +944,8 @@ int flush_io_cache(IO_CACHE *info)
...
@@ -932,6 +944,8 @@ int flush_io_cache(IO_CACHE *info)
info
->
end_of_file
+=
(
info
->
write_pos
-
info
->
append_read_pos
);
info
->
end_of_file
+=
(
info
->
write_pos
-
info
->
append_read_pos
);
info
->
append_read_pos
=
info
->
write_pos
=
info
->
write_buffer
;
info
->
append_read_pos
=
info
->
write_pos
=
info
->
write_buffer
;
if
(
need_append_buffer_lock
)
unlock_append_buffer
(
info
);
DBUG_RETURN
(
info
->
error
);
DBUG_RETURN
(
info
->
error
);
}
}
}
}
...
@@ -942,6 +956,8 @@ int flush_io_cache(IO_CACHE *info)
...
@@ -942,6 +956,8 @@ int flush_io_cache(IO_CACHE *info)
info
->
inited
=
0
;
info
->
inited
=
0
;
}
}
#endif
#endif
if
(
need_append_buffer_lock
)
unlock_append_buffer
(
info
);
DBUG_RETURN
(
0
);
DBUG_RETURN
(
0
);
}
}
...
...
mysys/my_getopt.c
0 → 100644
View file @
2e009645
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_config.h>
#include <my_global.h>
#include <m_string.h>
#include <stdlib.h>
#include <my_getopt.h>
#include <assert.h>
static
int
sortopt
(
int
*
argc
,
char
***
argv
);
static
int
findopt
(
char
*
optpat
,
uint
length
,
const
struct
my_option
**
opt_res
,
char
**
ffname
);
#define DISABLE_OPTION_COUNT 2
static
char
*
special_opt_prefix
[]
=
{
"skip"
,
"disable"
,
"enable"
,
0
};
/* function: handle_options
Sort options; put options first, until special end of options (--), or
until end of argv. Parse options; check that the given option matches with
one of the options in struct 'my_option', return error in case of ambiguous
or unknown option. Check that option was given an argument if it requires
one. Call function 'get_one_option()' once for each option.
*/
extern
int
handle_options
(
int
*
argc
,
char
***
argv
,
const
struct
my_option
*
longopts
,
my_bool
(
*
get_one_option
)(
int
,
const
struct
my_option
*
,
char
*
))
{
uint
opt_found
,
argvpos
=
0
,
length
,
spec_len
,
i
;
my_bool
end_of_options
=
0
,
must_be_var
=
0
;
char
*
progname
=
*
(
*
argv
),
**
pos
,
*
optend
,
*
prev_found
;
const
struct
my_option
*
optp
;
(
*
argc
)
--
;
(
*
argv
)
++
;
for
(
pos
=
*
argv
;
*
pos
;
pos
++
)
{
char
*
cur_arg
=
*
pos
;
if
(
*
cur_arg
==
'-'
&&
*
(
cur_arg
+
1
)
&&
!
end_of_options
)
// must be opt.
{
char
*
argument
=
0
;
must_be_var
=
0
;
// check for long option, or --set-variable (-O)
if
(
*
(
cur_arg
+
1
)
==
'-'
||
*
(
cur_arg
+
1
)
==
'O'
)
{
if
(
*
(
cur_arg
+
1
)
==
'O'
||
!
strncmp
(
cur_arg
,
"--set-variable"
,
14
))
{
must_be_var
=
1
;
if
(
*
(
cur_arg
+
1
)
==
'O'
)
{
cur_arg
+=
2
;
if
(
!
(
*
cur_arg
))
{
// the argument must be in next argv
if
(
!
(
*
(
pos
+
1
)))
{
fprintf
(
stderr
,
"%s: Option '-O' requires an argument
\n
"
,
progname
);
return
4
;
}
pos
++
;
cur_arg
=
*
pos
;
(
*
argc
)
--
;
}
}
else
// Option argument begins with string '--set-variable'
{
cur_arg
+=
14
;
if
(
*
cur_arg
==
'='
)
{
cur_arg
++
;
if
(
!
(
*
cur_arg
))
{
fprintf
(
stderr
,
"%s: Option '--set-variable' requires an argument
\n
"
,
progname
);
return
4
;
}
}
else
if
(
*
cur_arg
)
// garbage, or another option. break out
{
cur_arg
-=
14
;
must_be_var
=
0
;
}
else
{
// the argument must be in next argv
if
(
!
(
*
(
pos
+
1
)))
{
fprintf
(
stderr
,
"%s: Option '--set-variable' requires an argument
\n
"
,
progname
);
return
4
;
}
pos
++
;
cur_arg
=
*
pos
;
(
*
argc
)
--
;
}
}
}
else
if
(
!
must_be_var
)
{
if
(
!*
(
cur_arg
+
2
))
// '--' means end of options, look no further
{
end_of_options
=
1
;
(
*
argc
)
--
;
continue
;
}
cur_arg
+=
2
;
// skip the double dash
}
for
(
optend
=
cur_arg
;
*
optend
&&
*
optend
!=
'='
;
optend
++
)
;
length
=
optend
-
cur_arg
;
/*
Find first the right option. Return error in case of an ambiguous,
or unknown option
*/
optp
=
longopts
;
if
(
!
(
opt_found
=
findopt
(
cur_arg
,
length
,
&
optp
,
&
prev_found
)))
{
/*
Didn't find any matching option. Let's see if someone called
option with a special option prefix
*/
if
(
*
optend
!=
'='
&&
!
must_be_var
)
{
for
(
i
=
0
;
special_opt_prefix
[
i
];
i
++
)
{
spec_len
=
strlen
(
special_opt_prefix
[
i
]);
if
(
!
strncmp
(
special_opt_prefix
[
i
],
cur_arg
,
spec_len
)
&&
cur_arg
[
spec_len
]
==
'-'
)
{
// We were called with a special prefix, we can reuse opt_found
cur_arg
+=
(
spec_len
+
1
);
if
((
opt_found
=
findopt
(
cur_arg
,
length
-
(
spec_len
+
1
),
&
optp
,
&
prev_found
)))
{
if
(
opt_found
>
1
)
{
fprintf
(
stderr
,
"%s: ambiguous option '--%s-%s' (--%s-%s)
\n
"
,
progname
,
special_opt_prefix
[
i
],
cur_arg
,
special_opt_prefix
[
i
],
prev_found
);
return
2
;
}
if
(
i
<
DISABLE_OPTION_COUNT
)
optend
=
"=0"
;
else
// enable
optend
=
"=1"
;
break
;
// note break from the inner loop, main loop continues
}
}
}
}
if
(
!
opt_found
)
{
if
(
must_be_var
)
{
fprintf
(
stderr
,
"%s: unknown variable '%s'
\n
"
,
progname
,
cur_arg
);
return
7
;
}
else
{
fprintf
(
stderr
,
"%s: unknown option '--%s'
\n
"
,
progname
,
cur_arg
);
return
1
;
}
}
}
if
(
opt_found
>
1
)
{
if
(
must_be_var
)
{
fprintf
(
stderr
,
"%s: variable prefix '%s' is not unique
\n
"
,
progname
,
cur_arg
);
return
6
;
}
else
{
fprintf
(
stderr
,
"%s: ambiguous option '--%s' (%s, %s)
\n
"
,
progname
,
cur_arg
,
prev_found
,
optp
->
name
);
return
2
;
}
}
if
(
must_be_var
&&
!
optp
->
changeable_var
)
{
fprintf
(
stderr
,
"%s: the argument to -O must be a variable
\n
"
,
progname
);
return
8
;
}
if
(
optp
->
arg_type
==
NO_ARG
&&
*
optend
==
'='
)
{
fprintf
(
stderr
,
"%s: option '--%s' cannot take an argument
\n
"
,
progname
,
optp
->
name
);
return
3
;
}
else
if
(
optp
->
arg_type
==
REQUIRED_ARG
&&
!*
optend
)
{
/* Check if there are more arguments after this one */
if
(
!
(
*
(
pos
+
1
)))
{
fprintf
(
stderr
,
"%s: option '--%s' requires an argument
\n
"
,
progname
,
optp
->
name
);
return
4
;
}
pos
++
;
argument
=
*
pos
;
(
*
argc
)
--
;
}
else
if
(
*
optend
==
'='
)
argument
=
*
(
optend
+
1
)
?
optend
+
1
:
""
;
}
else
// must be short option
{
my_bool
skip
;
for
(
skip
=
0
,
optend
=
(
cur_arg
+
1
);
*
optend
&&
!
skip
;
optend
++
)
{
for
(
optp
=
longopts
;
optp
->
id
;
optp
++
)
{
if
(
optp
->
id
==
(
int
)
(
uchar
)
*
optend
)
{
/* Option recognized. Find next what to do with it */
if
(
optp
->
arg_type
==
REQUIRED_ARG
||
optp
->
arg_type
==
OPT_ARG
)
{
if
(
*
(
optend
+
1
))
{
argument
=
(
optend
+
1
);
/*
The rest of the option is option argument
This is in effect a jump out of this loop
*/
skip
=
1
;
}
else
if
(
optp
->
arg_type
==
REQUIRED_ARG
)
{
/* Check if there are more arguments after this one */
if
(
!
(
*
(
pos
+
1
)))
{
fprintf
(
stderr
,
"%s: option '-%c' requires an argument
\n
"
,
progname
,
optp
->
id
);
return
4
;
}
pos
++
;
argument
=
*
pos
;
(
*
argc
)
--
;
}
}
else
if
(
*
(
optend
+
1
))
// we are hitting many options in 1 argv
get_one_option
(
optp
->
id
,
optp
,
0
);
break
;
}
}
}
}
get_one_option
(
optp
->
id
,
optp
,
argument
);
(
*
argc
)
--
;
// option handled (short or long), decrease argument count
}
else
// non-option found
(
*
argv
)[
argvpos
++
]
=
cur_arg
;
}
return
0
;
}
/* function: findopt
Arguments: opt_pattern, length of opt_pattern, opt_struct, first found
name (ffname)
Go through all options in the my_option struct. Return number
of options found that match the pattern and in the argument
list the option found, if any. In case of ambiguous option, store
the name in ffname argument
*/
static
int
findopt
(
char
*
optpat
,
uint
length
,
const
struct
my_option
**
opt_res
,
char
**
ffname
)
{
int
count
;
struct
my_option
*
opt
=
(
struct
my_option
*
)
*
opt_res
;
for
(
count
=
0
;
opt
->
id
;
opt
++
)
{
if
(
!
strncmp
(
opt
->
name
,
optpat
,
length
))
// match found
{
(
*
opt_res
)
=
opt
;
if
(
!
count
)
*
ffname
=
(
char
*
)
opt
->
name
;
// we only need to know one prev
if
(
length
==
strlen
(
opt
->
name
))
// exact match
return
1
;
count
++
;
}
}
return
count
;
}
sql/log.cc
View file @
2e009645
...
@@ -703,12 +703,37 @@ void MYSQL_LOG::new_file(bool inside_mutex)
...
@@ -703,12 +703,37 @@ void MYSQL_LOG::new_file(bool inside_mutex)
}
}
}
}
bool
MYSQL_LOG
::
append
(
Log_event
*
ev
)
{
bool
error
=
0
;
pthread_mutex_lock
(
&
LOCK_log
);
DBUG_ASSERT
(
log_file
.
type
==
SEQ_READ_APPEND
);
// Log_event::write() is smart enough to use my_b_write() or
// my_b_append() depending on the kind of cache we have
if
(
ev
->
write
(
&
log_file
))
{
error
=
1
;
goto
err
;
}
if
((
uint
)
my_b_append_tell
(
&
log_file
)
>
max_binlog_size
)
{
new_file
(
1
);
}
signal_update
();
err:
pthread_mutex_unlock
(
&
LOCK_log
);
return
error
;
}
bool
MYSQL_LOG
::
appendv
(
const
char
*
buf
,
uint
len
,...)
bool
MYSQL_LOG
::
appendv
(
const
char
*
buf
,
uint
len
,...)
{
{
bool
error
=
0
;
bool
error
=
0
;
va_list
(
args
);
va_list
(
args
);
va_start
(
args
,
len
);
va_start
(
args
,
len
);
DBUG_ASSERT
(
log_file
.
type
==
SEQ_READ_APPEND
);
pthread_mutex_lock
(
&
LOCK_log
);
pthread_mutex_lock
(
&
LOCK_log
);
do
do
{
{
...
...
sql/log_event.cc
View file @
2e009645
...
@@ -26,6 +26,18 @@
...
@@ -26,6 +26,18 @@
#include <assert.h>
#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
if
(
file
->
type
==
SEQ_READ_APPEND
)
return
my_b_append
(
file
,
buf
,
len
);
return
my_b_write
(
file
,
buf
,
len
);
}
#ifdef MYSQL_CLIENT
#ifdef MYSQL_CLIENT
static
void
pretty_print_str
(
FILE
*
file
,
char
*
str
,
int
len
)
static
void
pretty_print_str
(
FILE
*
file
,
char
*
str
,
int
len
)
{
{
...
@@ -403,7 +415,7 @@ int Log_event::write_header(IO_CACHE* file)
...
@@ -403,7 +415,7 @@ int Log_event::write_header(IO_CACHE* file)
pos
+=
4
;
pos
+=
4
;
int2store
(
pos
,
flags
);
int2store
(
pos
,
flags
);
pos
+=
2
;
pos
+=
2
;
return
(
my_b_write
(
file
,
(
byte
*
)
buf
,
(
uint
)
(
pos
-
buf
)));
return
(
my_b_
safe_
write
(
file
,
(
byte
*
)
buf
,
(
uint
)
(
pos
-
buf
)));
}
}
#ifndef MYSQL_CLIENT
#ifndef MYSQL_CLIENT
...
@@ -677,7 +689,7 @@ int Start_log_event::write_data(IO_CACHE* file)
...
@@ -677,7 +689,7 @@ int Start_log_event::write_data(IO_CACHE* file)
int2store
(
buff
+
ST_BINLOG_VER_OFFSET
,
binlog_version
);
int2store
(
buff
+
ST_BINLOG_VER_OFFSET
,
binlog_version
);
memcpy
(
buff
+
ST_SERVER_VER_OFFSET
,
server_version
,
ST_SERVER_VER_LEN
);
memcpy
(
buff
+
ST_SERVER_VER_OFFSET
,
server_version
,
ST_SERVER_VER_LEN
);
int4store
(
buff
+
ST_CREATED_OFFSET
,
created
);
int4store
(
buff
+
ST_CREATED_OFFSET
,
created
);
return
(
my_b_write
(
file
,
(
byte
*
)
buff
,
sizeof
(
buff
))
?
-
1
:
0
);
return
(
my_b_
safe_
write
(
file
,
(
byte
*
)
buff
,
sizeof
(
buff
))
?
-
1
:
0
);
}
}
Rotate_log_event
::
Rotate_log_event
(
const
char
*
buf
,
int
event_len
,
Rotate_log_event
::
Rotate_log_event
(
const
char
*
buf
,
int
event_len
,
...
@@ -714,8 +726,8 @@ int Rotate_log_event::write_data(IO_CACHE* file)
...
@@ -714,8 +726,8 @@ int Rotate_log_event::write_data(IO_CACHE* file)
{
{
char
buf
[
ROTATE_HEADER_LEN
];
char
buf
[
ROTATE_HEADER_LEN
];
int8store
(
buf
,
pos
+
R_POS_OFFSET
);
int8store
(
buf
,
pos
+
R_POS_OFFSET
);
return
my_b_write
(
file
,
(
byte
*
)
buf
,
ROTATE_HEADER_LEN
)
||
return
my_b_
safe_
write
(
file
,
(
byte
*
)
buf
,
ROTATE_HEADER_LEN
)
||
my_b_write
(
file
,
(
byte
*
)
new_log_ident
,
(
uint
)
ident_len
);
my_b_
safe_
write
(
file
,
(
byte
*
)
new_log_ident
,
(
uint
)
ident_len
);
}
}
#ifndef MYSQL_CLIENT
#ifndef MYSQL_CLIENT
...
@@ -812,9 +824,9 @@ int Query_log_event::write_data(IO_CACHE* file)
...
@@ -812,9 +824,9 @@ int Query_log_event::write_data(IO_CACHE* file)
buf
[
Q_DB_LEN_OFFSET
]
=
(
char
)
db_len
;
buf
[
Q_DB_LEN_OFFSET
]
=
(
char
)
db_len
;
int2store
(
buf
+
Q_ERR_CODE_OFFSET
,
error_code
);
int2store
(
buf
+
Q_ERR_CODE_OFFSET
,
error_code
);
return
(
my_b_write
(
file
,
(
byte
*
)
buf
,
QUERY_HEADER_LEN
)
||
return
(
my_b_
safe_
write
(
file
,
(
byte
*
)
buf
,
QUERY_HEADER_LEN
)
||
my_b_write
(
file
,
(
db
)
?
(
byte
*
)
db
:
(
byte
*
)
""
,
db_len
+
1
)
||
my_b_
safe_
write
(
file
,
(
db
)
?
(
byte
*
)
db
:
(
byte
*
)
""
,
db_len
+
1
)
||
my_b_write
(
file
,
(
byte
*
)
query
,
q_len
))
?
-
1
:
0
;
my_b_
safe_
write
(
file
,
(
byte
*
)
query
,
q_len
))
?
-
1
:
0
;
}
}
Intvar_log_event
::
Intvar_log_event
(
const
char
*
buf
,
bool
old_format
)
:
Intvar_log_event
::
Intvar_log_event
(
const
char
*
buf
,
bool
old_format
)
:
...
@@ -840,7 +852,7 @@ int Intvar_log_event::write_data(IO_CACHE* file)
...
@@ -840,7 +852,7 @@ int Intvar_log_event::write_data(IO_CACHE* file)
char
buf
[
9
];
char
buf
[
9
];
buf
[
I_TYPE_OFFSET
]
=
type
;
buf
[
I_TYPE_OFFSET
]
=
type
;
int8store
(
buf
+
I_VAL_OFFSET
,
val
);
int8store
(
buf
+
I_VAL_OFFSET
,
val
);
return
my_b_write
(
file
,
(
byte
*
)
buf
,
sizeof
(
buf
));
return
my_b_
safe_
write
(
file
,
(
byte
*
)
buf
,
sizeof
(
buf
));
}
}
#ifdef MYSQL_CLIENT
#ifdef MYSQL_CLIENT
...
@@ -878,7 +890,7 @@ int Load_log_event::write_data_header(IO_CACHE* file)
...
@@ -878,7 +890,7 @@ int Load_log_event::write_data_header(IO_CACHE* file)
buf
[
L_TBL_LEN_OFFSET
]
=
(
char
)
table_name_len
;
buf
[
L_TBL_LEN_OFFSET
]
=
(
char
)
table_name_len
;
buf
[
L_DB_LEN_OFFSET
]
=
(
char
)
db_len
;
buf
[
L_DB_LEN_OFFSET
]
=
(
char
)
db_len
;
int4store
(
buf
+
L_NUM_FIELDS_OFFSET
,
num_fields
);
int4store
(
buf
+
L_NUM_FIELDS_OFFSET
,
num_fields
);
return
my_b_write
(
file
,
(
byte
*
)
buf
,
LOAD_HEADER_LEN
);
return
my_b_
safe_
write
(
file
,
(
byte
*
)
buf
,
LOAD_HEADER_LEN
);
}
}
int
Load_log_event
::
write_data_body
(
IO_CACHE
*
file
)
int
Load_log_event
::
write_data_body
(
IO_CACHE
*
file
)
...
@@ -886,20 +898,20 @@ int Load_log_event::write_data_body(IO_CACHE* file)
...
@@ -886,20 +898,20 @@ int Load_log_event::write_data_body(IO_CACHE* file)
if
(
sql_ex
.
write_data
(
file
))
return
1
;
if
(
sql_ex
.
write_data
(
file
))
return
1
;
if
(
num_fields
&&
fields
&&
field_lens
)
if
(
num_fields
&&
fields
&&
field_lens
)
{
{
if
(
my_b_write
(
file
,
(
byte
*
)
field_lens
,
num_fields
)
||
if
(
my_b_
safe_
write
(
file
,
(
byte
*
)
field_lens
,
num_fields
)
||
my_b_write
(
file
,
(
byte
*
)
fields
,
field_block_len
))
my_b_
safe_
write
(
file
,
(
byte
*
)
fields
,
field_block_len
))
return
1
;
return
1
;
}
}
return
(
my_b_write
(
file
,
(
byte
*
)
table_name
,
table_name_len
+
1
)
||
return
(
my_b_
safe_
write
(
file
,
(
byte
*
)
table_name
,
table_name_len
+
1
)
||
my_b_write
(
file
,
(
byte
*
)
db
,
db_len
+
1
)
||
my_b_
safe_
write
(
file
,
(
byte
*
)
db
,
db_len
+
1
)
||
my_b_write
(
file
,
(
byte
*
)
fname
,
fname_len
));
my_b_
safe_
write
(
file
,
(
byte
*
)
fname
,
fname_len
));
}
}
static
bool
write_str
(
IO_CACHE
*
file
,
char
*
str
,
byte
length
)
static
bool
write_str
(
IO_CACHE
*
file
,
char
*
str
,
byte
length
)
{
{
return
(
my_b_write
(
file
,
&
length
,
1
)
||
return
(
my_b_
safe_
write
(
file
,
&
length
,
1
)
||
my_b_write
(
file
,
(
byte
*
)
str
,
(
int
)
length
));
my_b_
safe_
write
(
file
,
(
byte
*
)
str
,
(
int
)
length
));
}
}
int
sql_ex_info
::
write_data
(
IO_CACHE
*
file
)
int
sql_ex_info
::
write_data
(
IO_CACHE
*
file
)
...
@@ -911,7 +923,7 @@ int sql_ex_info::write_data(IO_CACHE* file)
...
@@ -911,7 +923,7 @@ int sql_ex_info::write_data(IO_CACHE* file)
write_str
(
file
,
line_term
,
line_term_len
)
||
write_str
(
file
,
line_term
,
line_term_len
)
||
write_str
(
file
,
line_start
,
line_start_len
)
||
write_str
(
file
,
line_start
,
line_start_len
)
||
write_str
(
file
,
escaped
,
escaped_len
)
||
write_str
(
file
,
escaped
,
escaped_len
)
||
my_b_write
(
file
,(
byte
*
)
&
opt_flags
,
1
));
my_b_
safe_
write
(
file
,(
byte
*
)
&
opt_flags
,
1
));
}
}
else
else
{
{
...
@@ -923,7 +935,7 @@ int sql_ex_info::write_data(IO_CACHE* file)
...
@@ -923,7 +935,7 @@ int sql_ex_info::write_data(IO_CACHE* file)
old_ex
.
escaped
=
*
escaped
;
old_ex
.
escaped
=
*
escaped
;
old_ex
.
opt_flags
=
opt_flags
;
old_ex
.
opt_flags
=
opt_flags
;
old_ex
.
empty_flags
=
empty_flags
;
old_ex
.
empty_flags
=
empty_flags
;
return
my_b_write
(
file
,
(
byte
*
)
&
old_ex
,
sizeof
(
old_ex
));
return
my_b_
safe_
write
(
file
,
(
byte
*
)
&
old_ex
,
sizeof
(
old_ex
));
}
}
}
}
...
@@ -1280,7 +1292,7 @@ int Slave_log_event::write_data(IO_CACHE* file)
...
@@ -1280,7 +1292,7 @@ int Slave_log_event::write_data(IO_CACHE* file)
int8store
(
mem_pool
+
SL_MASTER_POS_OFFSET
,
master_pos
);
int8store
(
mem_pool
+
SL_MASTER_POS_OFFSET
,
master_pos
);
int2store
(
mem_pool
+
SL_MASTER_PORT_OFFSET
,
master_port
);
int2store
(
mem_pool
+
SL_MASTER_PORT_OFFSET
,
master_port
);
// log and host are already there
// log and host are already there
return
my_b_write
(
file
,
(
byte
*
)
mem_pool
,
get_data_size
());
return
my_b_
safe_
write
(
file
,
(
byte
*
)
mem_pool
,
get_data_size
());
}
}
void
Slave_log_event
::
init_from_mem_pool
(
int
data_size
)
void
Slave_log_event
::
init_from_mem_pool
(
int
data_size
)
...
@@ -1330,8 +1342,8 @@ int Create_file_log_event::write_data_body(IO_CACHE* file)
...
@@ -1330,8 +1342,8 @@ int Create_file_log_event::write_data_body(IO_CACHE* file)
int
res
;
int
res
;
if
((
res
=
Load_log_event
::
write_data_body
(
file
))
||
fake_base
)
if
((
res
=
Load_log_event
::
write_data_body
(
file
))
||
fake_base
)
return
res
;
return
res
;
return
(
my_b_write
(
file
,
(
byte
*
)
""
,
1
)
||
return
(
my_b_
safe_
write
(
file
,
(
byte
*
)
""
,
1
)
||
my_b_write
(
file
,
(
byte
*
)
block
,
block_len
));
my_b_
safe_
write
(
file
,
(
byte
*
)
block
,
block_len
));
}
}
int
Create_file_log_event
::
write_data_header
(
IO_CACHE
*
file
)
int
Create_file_log_event
::
write_data_header
(
IO_CACHE
*
file
)
...
@@ -1341,7 +1353,7 @@ int Create_file_log_event::write_data_header(IO_CACHE* file)
...
@@ -1341,7 +1353,7 @@ int Create_file_log_event::write_data_header(IO_CACHE* file)
return
res
;
return
res
;
byte
buf
[
CREATE_FILE_HEADER_LEN
];
byte
buf
[
CREATE_FILE_HEADER_LEN
];
int4store
(
buf
+
CF_FILE_ID_OFFSET
,
file_id
);
int4store
(
buf
+
CF_FILE_ID_OFFSET
,
file_id
);
return
my_b_write
(
file
,
buf
,
CREATE_FILE_HEADER_LEN
);
return
my_b_
safe_
write
(
file
,
buf
,
CREATE_FILE_HEADER_LEN
);
}
}
int
Create_file_log_event
::
write_base
(
IO_CACHE
*
file
)
int
Create_file_log_event
::
write_base
(
IO_CACHE
*
file
)
...
@@ -1423,8 +1435,8 @@ int Append_block_log_event::write_data(IO_CACHE* file)
...
@@ -1423,8 +1435,8 @@ int Append_block_log_event::write_data(IO_CACHE* file)
{
{
byte
buf
[
APPEND_BLOCK_HEADER_LEN
];
byte
buf
[
APPEND_BLOCK_HEADER_LEN
];
int4store
(
buf
+
AB_FILE_ID_OFFSET
,
file_id
);
int4store
(
buf
+
AB_FILE_ID_OFFSET
,
file_id
);
return
(
my_b_write
(
file
,
buf
,
APPEND_BLOCK_HEADER_LEN
)
||
return
(
my_b_
safe_
write
(
file
,
buf
,
APPEND_BLOCK_HEADER_LEN
)
||
my_b_write
(
file
,
(
byte
*
)
block
,
block_len
));
my_b_
safe_
write
(
file
,
(
byte
*
)
block
,
block_len
));
}
}
#ifdef MYSQL_CLIENT
#ifdef MYSQL_CLIENT
...
@@ -1473,7 +1485,7 @@ int Delete_file_log_event::write_data(IO_CACHE* file)
...
@@ -1473,7 +1485,7 @@ int Delete_file_log_event::write_data(IO_CACHE* file)
{
{
byte
buf
[
DELETE_FILE_HEADER_LEN
];
byte
buf
[
DELETE_FILE_HEADER_LEN
];
int4store
(
buf
+
DF_FILE_ID_OFFSET
,
file_id
);
int4store
(
buf
+
DF_FILE_ID_OFFSET
,
file_id
);
return
my_b_write
(
file
,
buf
,
DELETE_FILE_HEADER_LEN
);
return
my_b_
safe_
write
(
file
,
buf
,
DELETE_FILE_HEADER_LEN
);
}
}
#ifdef MYSQL_CLIENT
#ifdef MYSQL_CLIENT
...
@@ -1520,7 +1532,7 @@ int Execute_load_log_event::write_data(IO_CACHE* file)
...
@@ -1520,7 +1532,7 @@ int Execute_load_log_event::write_data(IO_CACHE* file)
{
{
byte
buf
[
EXEC_LOAD_HEADER_LEN
];
byte
buf
[
EXEC_LOAD_HEADER_LEN
];
int4store
(
buf
+
EL_FILE_ID_OFFSET
,
file_id
);
int4store
(
buf
+
EL_FILE_ID_OFFSET
,
file_id
);
return
my_b_write
(
file
,
buf
,
EXEC_LOAD_HEADER_LEN
);
return
my_b_
safe_
write
(
file
,
buf
,
EXEC_LOAD_HEADER_LEN
);
}
}
#ifdef MYSQL_CLIENT
#ifdef MYSQL_CLIENT
...
...
sql/slave.cc
View file @
2e009645
...
@@ -54,6 +54,9 @@ static int stuck_count = 0;
...
@@ -54,6 +54,9 @@ static int stuck_count = 0;
typedef
enum
{
SLAVE_THD_IO
,
SLAVE_THD_SQL
}
SLAVE_THD_TYPE
;
typedef
enum
{
SLAVE_THD_IO
,
SLAVE_THD_SQL
}
SLAVE_THD_TYPE
;
void
skip_load_data_infile
(
NET
*
net
);
void
skip_load_data_infile
(
NET
*
net
);
static
int
process_io_rotate
(
MASTER_INFO
*
mi
,
Rotate_log_event
*
rev
);
static
int
queue_old_event
(
MASTER_INFO
*
mi
,
const
char
*
buf
,
uint
event_len
);
static
inline
bool
slave_killed
(
THD
*
thd
,
MASTER_INFO
*
mi
);
static
inline
bool
slave_killed
(
THD
*
thd
,
MASTER_INFO
*
mi
);
static
inline
bool
slave_killed
(
THD
*
thd
,
RELAY_LOG_INFO
*
rli
);
static
inline
bool
slave_killed
(
THD
*
thd
,
RELAY_LOG_INFO
*
rli
);
static
int
init_slave_thread
(
THD
*
thd
,
SLAVE_THD_TYPE
thd_type
);
static
int
init_slave_thread
(
THD
*
thd
,
SLAVE_THD_TYPE
thd_type
);
...
@@ -1918,34 +1921,86 @@ the slave SQL thread with \"mysqladmin start-slave\". We stopped at log \
...
@@ -1918,34 +1921,86 @@ the slave SQL thread with \"mysqladmin start-slave\". We stopped at log \
DBUG_RETURN
(
0
);
// Can't return anything here
DBUG_RETURN
(
0
);
// Can't return anything here
}
}
static
int
process_io_rotate
(
MASTER_INFO
*
mi
,
Rotate_log_event
*
rev
)
{
if
(
!
rev
->
is_valid
())
return
1
;
DBUG_ASSERT
(
rev
->
ident_len
<
sizeof
(
mi
->
master_log_name
));
memcpy
(
mi
->
master_log_name
,
rev
->
new_log_ident
,
rev
->
ident_len
);
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
++
;
#endif
return
0
;
}
static
int
queue_old_event
(
MASTER_INFO
*
mi
,
const
char
*
buf
,
uint
event_len
)
{
const
char
*
errmsg
=
0
;
bool
inc_pos
=
1
;
Log_event
*
ev
=
Log_event
::
read_log_event
(
buf
,
event_len
,
&
errmsg
,
1
/*old format*/
);
if
(
!
ev
)
{
sql_print_error
(
"Read invalid event from master: '%s',\
master could be corrupt but a more likely cause of this is a bug"
,
errmsg
);
return
1
;
}
ev
->
log_pos
=
mi
->
master_log_pos
;
switch
(
ev
->
get_type_code
())
{
case
ROTATE_EVENT
:
if
(
process_io_rotate
(
mi
,(
Rotate_log_event
*
)
ev
))
{
delete
ev
;
return
1
;
}
inc_pos
=
0
;
break
;
case
LOAD_EVENT
:
// TODO: actually process it
mi
->
master_log_pos
+=
event_len
;
return
0
;
break
;
default:
break
;
}
if
(
mi
->
rli
.
relay_log
.
append
(
ev
))
{
delete
ev
;
return
1
;
}
delete
ev
;
if
(
inc_pos
)
mi
->
master_log_pos
+=
event_len
;
return
0
;
}
int
queue_event
(
MASTER_INFO
*
mi
,
const
char
*
buf
,
uint
event_len
)
int
queue_event
(
MASTER_INFO
*
mi
,
const
char
*
buf
,
uint
event_len
)
{
{
int
error
;
int
error
;
bool
inc_pos
=
1
;
bool
inc_pos
=
1
;
if
(
mi
->
old_format
)
if
(
mi
->
old_format
)
return
1
;
// TODO: deal with old format
return
queue_old_event
(
mi
,
buf
,
event_len
);
// TODO: figure out if other events in addition to Rotate
// require special processing
switch
(
buf
[
EVENT_TYPE_OFFSET
])
switch
(
buf
[
EVENT_TYPE_OFFSET
])
{
{
case
ROTATE_EVENT
:
case
ROTATE_EVENT
:
{
{
Rotate_log_event
rev
(
buf
,
event_len
,
0
);
Rotate_log_event
rev
(
buf
,
event_len
,
0
);
if
(
!
rev
.
is_valid
(
))
if
(
process_io_rotate
(
mi
,
&
rev
))
return
1
;
return
1
;
DBUG_ASSERT
(
rev
.
ident_len
<
sizeof
(
mi
->
master_log_name
));
inc_pos
=
0
;
memcpy
(
mi
->
master_log_name
,
rev
.
new_log_ident
,
rev
.
ident_len
);
mi
->
master_log_name
[
rev
.
ident_len
]
=
0
;
mi
->
master_log_pos
=
rev
.
pos
;
inc_pos
=
0
;
#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
++
;
#endif
break
;
break
;
}
}
default:
default:
...
...
sql/sql_class.h
View file @
2e009645
...
@@ -108,6 +108,7 @@ class MYSQL_LOG {
...
@@ -108,6 +108,7 @@ class MYSQL_LOG {
//v stands for vector
//v stands for vector
//invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0)
//invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0)
bool
appendv
(
const
char
*
buf
,
uint
len
,...);
bool
appendv
(
const
char
*
buf
,
uint
len
,...);
bool
append
(
Log_event
*
ev
);
int
generate_new_name
(
char
*
new_name
,
const
char
*
old_name
);
int
generate_new_name
(
char
*
new_name
,
const
char
*
old_name
);
void
make_log_name
(
char
*
buf
,
const
char
*
log_ident
);
void
make_log_name
(
char
*
buf
,
const
char
*
log_ident
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment