Commit 1fc7f211 authored by unknown's avatar unknown

WL#2936

  "Server Variables for Plugins"
  Implement support for plugins to declare server variables.
  Demonstrate functionality by removing InnoDB specific code from sql/*
  New feature for HASH - HASH_UNIQUE flag
  New feature for DYNAMIC_ARRAY - initializer accepts preallocated ptr.
  Completed support for plugin reference counting.


include/hash.h:
  New flag for HASH
    HASH_UNIQUE
include/my_getopt.h:
  New data types for options: ENUM and SET.
  Use typelib to enumerate possible values.
  New flag variable:
    my_getopt_skip_unknown
include/my_sys.h:
  change to DYNAMIC_ARRAY init functions to support pre-allocated buffers
include/mysql.h:
  relocate inclusion of typelib due to longlong requirement
include/mysql/plugin.h:
  wl2936
    New declarations for plugin server variable support.
    New functions for use by plugins
include/mysys_err.h:
  new my_getopt return value: EXIT_ARGUMENT_INVALID
include/typelib.h:
  new typelib function: find_typeset(), returns an int which is a SET of
  the elements in the typelib
mysql-test/r/im_utils.result:
  change to more specific command line settings
  --skip-innodb => --skip-plugin-innodb
  etc.
mysql-test/r/log_tables.result:
  set default storage engine to MEMORY so that test will succeed even
  when some of the other named storage engines are not present
mysql-test/r/ndb_dd_basic.result:
  change in error message
mysql-test/r/partition_innodb.result:
  change in results
mysql-test/r/ps_1general.result:
  bdb doesn't exist, use myisam for a non-transactional engine
mysql-test/r/variables.result:
  information schema doesn't sort row results for server variables.
mysql-test/t/log_tables.test:
  set default storage engine to MEMORY so that test will succeed even
  when some of the other named storage engines are not present
mysql-test/t/ndb_dd_basic.test:
  ALTER LOGFILE GROUP no longer silently fail here
mysql-test/t/partition_innodb.test:
  ALTER TABLE no longer silently fails for unknown storage engine
mysql-test/t/ps_1general.test:
  remove unneccessary parts
  use myisam as it is an always present non-transactional engine
mysql-test/t/variables.test:
  information schema doesn't sort row results for server variables.
mysql-test/t/warnings_engine_disabled-master.opt:
  use the new style command line option
mysys/array.c:
  change to DYNAMIC_ARRAY init functions to support pre-allocated buffers
mysys/hash.c:
  New flag for HASH
    HASH_UNIQUE
  Implement HASH_UNIQUE functionality by performing a hash_search
mysys/my_getopt.c:
  New data types for options: ENUM and SET.
  Use typelib to enumerate possible values.
  New flag variable:
    my_getopt_skip_unknown
mysys/typelib.c:
  new typelib function: find_typeset(), returns an int which is a SET of
  the elements in the typelib
sql/ha_ndbcluster.cc:
  use ha_statistic_increment() method instead of
  statistic_increment() function
  ha_ndbcluster variable has gone away.
sql/ha_partition.cc:
  fix for reference counting
sql/ha_partition.h:
  fix for reference counting
sql/handler.cc:
  fixes for reference counting
sql/handler.h:
  fixes for reference counting
  some new methods to aid storage engine writers
sql/item_func.cc:
  find_sys_var() function now requires thd
sql/item_sum.cc:
  fixes for ref counting
sql/mysql_priv.h:
  remove unneccessary globals.
  new lock: LOCK_system_variables_hash
sql/mysqld.cc:
  Remove InnoBase specific code.
  Support plugin command line processing.
sql/set_var.cc:
  Remove InnoBase specific declarations
  Remove redundant declarations
  changes to permit new variables at run time
  changes for ref counting
sql/set_var.h:
  changes to permit new variables at run time
  changes for ref counting
sql/sql_base.cc:
  changes for ref counting
sql/sql_cache.cc:
  mark code as needing work in the future
sql/sql_class.cc:
  new functions to aid plugin authors
  initialize variables for dynamic plugin variables
sql/sql_class.h:
  remove InnoBase specific declarations
  New declarations for plugin variables.
sql/sql_connect.cc:
  initialization and cleanup of plugin variables
sql/sql_delete.cc:
  change for ref counting
sql/sql_insert.cc:
  change for ref counting
sql/sql_lex.cc:
  changes for ref counting and plugin variables
sql/sql_lex.h:
  add properties for plugin ref counting,
  add to distructor to clean up
sql/sql_partition.cc:
  changes for ref counting
sql/sql_plugin.cc:
  WL2936
    Plugin Variables
    New methods and code to support server variables for plugins.
    New code to complete plugin reference counting
    Debug code adds further indirection so that malloc debugging can be
    used to aid finding plugin ref count leaks
sql/sql_plugin.h:
  WL2936
    Plugin Variables
    New methods and code to support server variables for plugins.
    New code to complete plugin reference counting
    Debug code adds further indirection so that malloc debugging can be
    used to aid finding plugin ref count leaks
sql/sql_repl.cc:
  replication system variables moved here from set_var.cc
sql/sql_repl.h:
  new function to initialise replication server variables
sql/sql_select.cc:
  changes for ref counting
sql/sql_show.cc:
  changes for ref counting
sql/sql_table.cc:
  changes for ref counting
sql/sql_tablespace.cc:
  use supplied functions instead of digging into data structures manually
sql/sql_yacc.yy:
  changes for ref counting
  find_sys_var() now requires thd parameter
  changes on reporting errors to keep user-visible behaviour the same.
sql/structs.h:
  changes for ref counting
sql/table.cc:
  changes for ref counting
sql/table.h:
  changes for ref counting
storage/federated/ha_federated.cc:
  use ha_statistic_increment() method instead of statistic_increment()
  function
storage/heap/ha_heap.cc:
  use ha_statistic_increment() method instead of statistic_increment()
  function
storage/innobase/handler/ha_innodb.cc:
  use ha_statistic_increment() method instead of statistic_increment()
  function
  WL2936
    Move InnoBase specific code out of mysqld.cc and into here
    Declare all required server variables for InnoBase
storage/innobase/include/trx0trx.h:
  store a bit more state so that InnoBase does not have to dig into
  mysqld internal data structures.
storage/myisam/ha_myisam.cc:
  use ha_statistic_increment() method instead of statistic_increment()
  function
storage/myisammrg/ha_myisammrg.cc:
  use ha_statistic_increment() method instead of statistic_increment()
  function
parent 1eb71c68
...@@ -27,6 +27,9 @@ extern "C" { ...@@ -27,6 +27,9 @@ extern "C" {
*/ */
#define HASH_OVERHEAD (sizeof(char*)*2) #define HASH_OVERHEAD (sizeof(char*)*2)
/* flags for hash_init */
#define HASH_UNIQUE 1 /* hash_insert fails on duplicate key */
typedef byte *(*hash_get_key)(const byte *,uint*,my_bool); typedef byte *(*hash_get_key)(const byte *,uint*,my_bool);
typedef void (*hash_free_key)(void *); typedef void (*hash_free_key)(void *);
......
...@@ -29,12 +29,16 @@ C_MODE_START ...@@ -29,12 +29,16 @@ C_MODE_START
#define GET_STR 9 #define GET_STR 9
#define GET_STR_ALLOC 10 #define GET_STR_ALLOC 10
#define GET_DISABLED 11 #define GET_DISABLED 11
#define GET_ENUM 12
#define GET_SET 13
#define GET_ASK_ADDR 128 #define GET_ASK_ADDR 128
#define GET_TYPE_MASK 127 #define GET_TYPE_MASK 127
enum get_opt_arg_type { NO_ARG, OPT_ARG, REQUIRED_ARG }; enum get_opt_arg_type { NO_ARG, OPT_ARG, REQUIRED_ARG };
struct st_typelib;
struct my_option struct my_option
{ {
const char *name; /* Name of the option */ const char *name; /* Name of the option */
...@@ -42,7 +46,7 @@ struct my_option ...@@ -42,7 +46,7 @@ struct my_option
const char *comment; /* option comment, for autom. --help */ const char *comment; /* option comment, for autom. --help */
gptr *value; /* The variable value */ gptr *value; /* The variable value */
gptr *u_max_value; /* The user def. max variable value */ gptr *u_max_value; /* The user def. max variable value */
const char **str_values; /* Pointer to possible values */ struct st_typelib *typelib; /* Pointer to possible values */
ulong var_type; ulong var_type;
enum get_opt_arg_type arg_type; enum get_opt_arg_type arg_type;
longlong def_value; /* Default value */ longlong def_value; /* Default value */
...@@ -50,7 +54,7 @@ struct my_option ...@@ -50,7 +54,7 @@ struct my_option
longlong max_value; /* Max allowed value */ longlong max_value; /* Max allowed value */
longlong sub_size; /* Subtract this from given value */ longlong sub_size; /* Subtract this from given value */
long block_size; /* Value should be a mult. of this */ long block_size; /* Value should be a mult. of this */
int app_type; /* To be used by an application */ long app_type; /* To be used by an application */
}; };
typedef my_bool (* my_get_one_option) (int, const struct my_option *, char * ); typedef my_bool (* my_get_one_option) (int, const struct my_option *, char * );
...@@ -58,6 +62,7 @@ typedef void (* my_error_reporter) (enum loglevel level, const char *format, ... ...@@ -58,6 +62,7 @@ typedef void (* my_error_reporter) (enum loglevel level, const char *format, ...
extern char *disabled_my_option; extern char *disabled_my_option;
extern my_bool my_getopt_print_errors; extern my_bool my_getopt_print_errors;
extern my_bool my_getopt_skip_unknown;
extern my_error_reporter my_getopt_error_reporter; extern my_error_reporter my_getopt_error_reporter;
extern int handle_options (int *argc, char ***argv, extern int handle_options (int *argc, char ***argv,
......
...@@ -758,8 +758,15 @@ extern my_bool real_open_cached_file(IO_CACHE *cache); ...@@ -758,8 +758,15 @@ extern my_bool real_open_cached_file(IO_CACHE *cache);
extern void close_cached_file(IO_CACHE *cache); extern void close_cached_file(IO_CACHE *cache);
File create_temp_file(char *to, const char *dir, const char *pfx, File create_temp_file(char *to, const char *dir, const char *pfx,
int mode, myf MyFlags); int mode, myf MyFlags);
#define my_init_dynamic_array(A,B,C,D) init_dynamic_array(A,B,C,D CALLER_INFO) #define my_init_dynamic_array(A,B,C,D) init_dynamic_array2(A,B,NULL,C,D CALLER_INFO)
#define my_init_dynamic_array_ci(A,B,C,D) init_dynamic_array(A,B,C,D ORIG_CALLER_INFO) #define my_init_dynamic_array_ci(A,B,C,D) init_dynamic_array2(A,B,NULL,C,D ORIG_CALLER_INFO)
#define my_init_dynamic_array2(A,B,C,D,E) init_dynamic_array2(A,B,C,D,E CALLER_INFO)
#define my_init_dynamic_array2_ci(A,B,C,D,E) init_dynamic_array2(A,B,C,D,E ORIG_CALLER_INFO)
extern my_bool init_dynamic_array2(DYNAMIC_ARRAY *array,uint element_size,
void *init_buffer, uint init_alloc,
uint alloc_increment
CALLER_INFO_PROTO);
/* init_dynamic_array() function is deprecated */
extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size, extern my_bool init_dynamic_array(DYNAMIC_ARRAY *array,uint element_size,
uint init_alloc,uint alloc_increment uint init_alloc,uint alloc_increment
CALLER_INFO_PROTO); CALLER_INFO_PROTO);
......
...@@ -67,7 +67,6 @@ typedef int my_socket; ...@@ -67,7 +67,6 @@ typedef int my_socket;
#include "mysql_version.h" #include "mysql_version.h"
#include "mysql_com.h" #include "mysql_com.h"
#include "mysql_time.h" #include "mysql_time.h"
#include "typelib.h"
#include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */ #include "my_list.h" /* for LISTs used in 'MYSQL' and 'MYSQL_STMT' */
...@@ -126,6 +125,8 @@ typedef unsigned long long my_ulonglong; ...@@ -126,6 +125,8 @@ typedef unsigned long long my_ulonglong;
#endif #endif
#endif #endif
#include "typelib.h"
#define MYSQL_COUNT_ERROR (~(my_ulonglong) 0) #define MYSQL_COUNT_ERROR (~(my_ulonglong) 0)
/* backward compatibility define - to be removed eventually */ /* backward compatibility define - to be removed eventually */
......
This diff is collapsed.
...@@ -79,6 +79,7 @@ extern const char * NEAR globerrs[]; /* my_error_messages is here */ ...@@ -79,6 +79,7 @@ extern const char * NEAR globerrs[]; /* my_error_messages is here */
#define EXIT_NO_PTR_TO_VARIABLE 10 #define EXIT_NO_PTR_TO_VARIABLE 10
#define EXIT_CANNOT_CONNECT_TO_SERVICE 11 #define EXIT_CANNOT_CONNECT_TO_SERVICE 11
#define EXIT_OPTION_DISABLED 12 #define EXIT_OPTION_DISABLED 12
#define EXIT_ARGUMENT_INVALID 13
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -26,6 +26,7 @@ typedef struct st_typelib { /* Different types saved here */ ...@@ -26,6 +26,7 @@ typedef struct st_typelib { /* Different types saved here */
unsigned int *type_lengths; unsigned int *type_lengths;
} TYPELIB; } TYPELIB;
extern my_ulonglong find_typeset(char *x, TYPELIB *typelib,int *error_position);
extern int find_type(char *x,TYPELIB *typelib,unsigned int full_name); extern int find_type(char *x,TYPELIB *typelib,unsigned int full_name);
extern void make_type(char *to,unsigned int nr,TYPELIB *typelib); extern void make_type(char *to,unsigned int nr,TYPELIB *typelib);
extern const char *get_type(TYPELIB *typelib,unsigned int nr); extern const char *get_type(TYPELIB *typelib,unsigned int nr);
......
...@@ -20,8 +20,8 @@ character-sets-dir VALUE ...@@ -20,8 +20,8 @@ character-sets-dir VALUE
basedir VALUE basedir VALUE
server_id VALUE server_id VALUE
skip-stack-trace VALUE skip-stack-trace VALUE
skip-innodb VALUE skip-plugin-innodb VALUE
skip-ndbcluster VALUE skip-plugin-ndbcluster VALUE
log-output VALUE log-output VALUE
SHOW INSTANCE OPTIONS mysqld2; SHOW INSTANCE OPTIONS mysqld2;
option_name value option_name value
...@@ -38,8 +38,8 @@ character-sets-dir VALUE ...@@ -38,8 +38,8 @@ character-sets-dir VALUE
basedir VALUE basedir VALUE
server_id VALUE server_id VALUE
skip-stack-trace VALUE skip-stack-trace VALUE
skip-innodb VALUE skip-plugin-innodb VALUE
skip-ndbcluster VALUE skip-plugin-ndbcluster VALUE
nonguarded VALUE nonguarded VALUE
log-output VALUE log-output VALUE
START INSTANCE mysqld2; START INSTANCE mysqld2;
......
...@@ -169,6 +169,8 @@ lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL; ...@@ -169,6 +169,8 @@ lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL;
unlock tables; unlock tables;
set global general_log='OFF'; set global general_log='OFF';
set global slow_query_log='OFF'; set global slow_query_log='OFF';
set @save_storage_engine= @@session.storage_engine;
set storage_engine= MEMORY;
alter table mysql.slow_log engine=ndb; alter table mysql.slow_log engine=ndb;
ERROR HY000: This storage engine cannot be used for log tables" ERROR HY000: This storage engine cannot be used for log tables"
alter table mysql.slow_log engine=innodb; alter table mysql.slow_log engine=innodb;
...@@ -177,6 +179,7 @@ alter table mysql.slow_log engine=archive; ...@@ -177,6 +179,7 @@ alter table mysql.slow_log engine=archive;
ERROR HY000: This storage engine cannot be used for log tables" ERROR HY000: This storage engine cannot be used for log tables"
alter table mysql.slow_log engine=blackhole; alter table mysql.slow_log engine=blackhole;
ERROR HY000: This storage engine cannot be used for log tables" ERROR HY000: This storage engine cannot be used for log tables"
set storage_engine= @save_storage_engine;
drop table mysql.slow_log; drop table mysql.slow_log;
drop table mysql.general_log; drop table mysql.general_log;
drop table mysql.general_log; drop table mysql.general_log;
......
...@@ -10,9 +10,7 @@ ALTER LOGFILE GROUP lg1 ...@@ -10,9 +10,7 @@ ALTER LOGFILE GROUP lg1
ADD UNDOFILE 'undofile02.dat' ADD UNDOFILE 'undofile02.dat'
INITIAL_SIZE = 4M INITIAL_SIZE = 4M
ENGINE=XYZ; ENGINE=XYZ;
Warnings: ERROR 42000: Unknown table engine 'XYZ'
Error 1286 Unknown table engine 'XYZ'
Error 1466 Table storage engine 'MyISAM' does not support the create option 'TABLESPACE or LOGFILE GROUP'
CREATE TABLESPACE ts1 CREATE TABLESPACE ts1
ADD DATAFILE 'datafile.dat' ADD DATAFILE 'datafile.dat'
USE LOGFILE GROUP lg1 USE LOGFILE GROUP lg1
......
...@@ -54,7 +54,7 @@ create table t1 (a int) ...@@ -54,7 +54,7 @@ create table t1 (a int)
engine = x engine = x
partition by key (a); partition by key (a);
Warnings: Warnings:
Error 1286 Unknown table engine 'x' Warning 1266 Using storage engine MyISAM for table 't1'
show create table t1; show create table t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
...@@ -66,8 +66,7 @@ engine = innodb ...@@ -66,8 +66,7 @@ engine = innodb
partition by list (a) partition by list (a)
(partition p0 values in (0)); (partition p0 values in (0));
alter table t1 engine = x; alter table t1 engine = x;
Warnings: ERROR 42000: Unknown table engine 'x'
Error 1286 Unknown table engine 'x'
show create table t1; show create table t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
......
...@@ -303,8 +303,9 @@ prepare stmt4 from ' show variables like ''sql_mode'' '; ...@@ -303,8 +303,9 @@ prepare stmt4 from ' show variables like ''sql_mode'' ';
execute stmt4; execute stmt4;
Variable_name Value Variable_name Value
sql_mode sql_mode
prepare stmt4 from ' show engine bdb logs '; prepare stmt4 from ' show engine myisam logs ';
execute stmt4; execute stmt4;
Type Name Status
prepare stmt4 from ' show grants for user '; prepare stmt4 from ' show grants for user ';
prepare stmt4 from ' show create table t2 '; prepare stmt4 from ' show create table t2 ';
prepare stmt4 from ' show master status '; prepare stmt4 from ' show master status ';
......
...@@ -236,7 +236,7 @@ net_buffer_length 1024 ...@@ -236,7 +236,7 @@ net_buffer_length 1024
net_read_timeout 300 net_read_timeout 300
net_retry_count 10 net_retry_count 10
net_write_timeout 200 net_write_timeout 200
select * from information_schema.global_variables where variable_name like 'net_%'; select * from information_schema.global_variables where variable_name like 'net_%' order by 1;
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
NET_BUFFER_LENGTH 1024 NET_BUFFER_LENGTH 1024
NET_READ_TIMEOUT 300 NET_READ_TIMEOUT 300
...@@ -248,7 +248,7 @@ net_buffer_length 2048 ...@@ -248,7 +248,7 @@ net_buffer_length 2048
net_read_timeout 600 net_read_timeout 600
net_retry_count 10 net_retry_count 10
net_write_timeout 500 net_write_timeout 500
select * from information_schema.session_variables where variable_name like 'net_%'; select * from information_schema.session_variables where variable_name like 'net_%' order by 1;
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
NET_BUFFER_LENGTH 2048 NET_BUFFER_LENGTH 2048
NET_READ_TIMEOUT 600 NET_READ_TIMEOUT 600
...@@ -261,7 +261,7 @@ net_buffer_length 1024 ...@@ -261,7 +261,7 @@ net_buffer_length 1024
net_read_timeout 900 net_read_timeout 900
net_retry_count 10 net_retry_count 10
net_write_timeout 1000 net_write_timeout 1000
select * from information_schema.global_variables where variable_name like 'net_%'; select * from information_schema.global_variables where variable_name like 'net_%' order by 1;
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
NET_BUFFER_LENGTH 1024 NET_BUFFER_LENGTH 1024
NET_READ_TIMEOUT 900 NET_READ_TIMEOUT 900
...@@ -273,7 +273,7 @@ net_buffer_length 7168 ...@@ -273,7 +273,7 @@ net_buffer_length 7168
net_read_timeout 600 net_read_timeout 600
net_retry_count 10 net_retry_count 10
net_write_timeout 500 net_write_timeout 500
select * from information_schema.session_variables where variable_name like 'net_%'; select * from information_schema.session_variables where variable_name like 'net_%' order by 1;
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
NET_BUFFER_LENGTH 7168 NET_BUFFER_LENGTH 7168
NET_READ_TIMEOUT 600 NET_READ_TIMEOUT 600
...@@ -314,7 +314,7 @@ query_prealloc_size 8192 ...@@ -314,7 +314,7 @@ query_prealloc_size 8192
range_alloc_block_size 2048 range_alloc_block_size 2048
transaction_alloc_block_size 8192 transaction_alloc_block_size 8192
transaction_prealloc_size 4096 transaction_prealloc_size 4096
select * from information_schema.session_variables where variable_name like '%alloc%'; select * from information_schema.session_variables where variable_name like '%alloc%' order by 1;
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
QUERY_ALLOC_BLOCK_SIZE 8192 QUERY_ALLOC_BLOCK_SIZE 8192
QUERY_PREALLOC_SIZE 8192 QUERY_PREALLOC_SIZE 8192
...@@ -336,7 +336,7 @@ query_prealloc_size 18432 ...@@ -336,7 +336,7 @@ query_prealloc_size 18432
range_alloc_block_size 16384 range_alloc_block_size 16384
transaction_alloc_block_size 19456 transaction_alloc_block_size 19456
transaction_prealloc_size 20480 transaction_prealloc_size 20480
select * from information_schema.session_variables where variable_name like '%alloc%'; select * from information_schema.session_variables where variable_name like '%alloc%' order by 1;
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
QUERY_ALLOC_BLOCK_SIZE 17408 QUERY_ALLOC_BLOCK_SIZE 17408
QUERY_PREALLOC_SIZE 18432 QUERY_PREALLOC_SIZE 18432
...@@ -353,7 +353,7 @@ query_prealloc_size 8192 ...@@ -353,7 +353,7 @@ query_prealloc_size 8192
range_alloc_block_size 2048 range_alloc_block_size 2048
transaction_alloc_block_size 8192 transaction_alloc_block_size 8192
transaction_prealloc_size 4096 transaction_prealloc_size 4096
select * from information_schema.session_variables where variable_name like '%alloc%'; select * from information_schema.session_variables where variable_name like '%alloc%' order by 1;
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
QUERY_ALLOC_BLOCK_SIZE 8192 QUERY_ALLOC_BLOCK_SIZE 8192
QUERY_PREALLOC_SIZE 8192 QUERY_PREALLOC_SIZE 8192
...@@ -881,7 +881,7 @@ ssl_capath # ...@@ -881,7 +881,7 @@ ssl_capath #
ssl_cert # ssl_cert #
ssl_cipher # ssl_cipher #
ssl_key # ssl_key #
select * from information_schema.session_variables where variable_name like 'ssl%'; select * from information_schema.session_variables where variable_name like 'ssl%' order by 1;
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
SSL_CA # SSL_CA #
SSL_CAPATH # SSL_CAPATH #
......
...@@ -252,6 +252,8 @@ set global general_log='OFF'; ...@@ -252,6 +252,8 @@ set global general_log='OFF';
set global slow_query_log='OFF'; set global slow_query_log='OFF';
# check that alter table doesn't work for other engines # check that alter table doesn't work for other engines
set @save_storage_engine= @@session.storage_engine;
set storage_engine= MEMORY;
--error ER_UNSUPORTED_LOG_ENGINE --error ER_UNSUPORTED_LOG_ENGINE
alter table mysql.slow_log engine=ndb; alter table mysql.slow_log engine=ndb;
--error ER_UNSUPORTED_LOG_ENGINE --error ER_UNSUPORTED_LOG_ENGINE
...@@ -260,6 +262,7 @@ alter table mysql.slow_log engine=innodb; ...@@ -260,6 +262,7 @@ alter table mysql.slow_log engine=innodb;
alter table mysql.slow_log engine=archive; alter table mysql.slow_log engine=archive;
--error ER_UNSUPORTED_LOG_ENGINE --error ER_UNSUPORTED_LOG_ENGINE
alter table mysql.slow_log engine=blackhole; alter table mysql.slow_log engine=blackhole;
set storage_engine= @save_storage_engine;
drop table mysql.slow_log; drop table mysql.slow_log;
drop table mysql.general_log; drop table mysql.general_log;
......
...@@ -21,6 +21,7 @@ INITIAL_SIZE 16M ...@@ -21,6 +21,7 @@ INITIAL_SIZE 16M
UNDO_BUFFER_SIZE = 1M UNDO_BUFFER_SIZE = 1M
ENGINE=MYISAM; ENGINE=MYISAM;
--error ER_UNKNOWN_STORAGE_ENGINE
ALTER LOGFILE GROUP lg1 ALTER LOGFILE GROUP lg1
ADD UNDOFILE 'undofile02.dat' ADD UNDOFILE 'undofile02.dat'
INITIAL_SIZE = 4M INITIAL_SIZE = 4M
......
...@@ -71,6 +71,7 @@ engine = innodb ...@@ -71,6 +71,7 @@ engine = innodb
partition by list (a) partition by list (a)
(partition p0 values in (0)); (partition p0 values in (0));
--error ER_UNKNOWN_STORAGE_ENGINE
alter table t1 engine = x; alter table t1 engine = x;
show create table t1; show create table t1;
drop table t1; drop table t1;
......
...@@ -321,14 +321,8 @@ prepare stmt4 from ' show status like ''Threads_running'' '; ...@@ -321,14 +321,8 @@ prepare stmt4 from ' show status like ''Threads_running'' ';
execute stmt4; execute stmt4;
prepare stmt4 from ' show variables like ''sql_mode'' '; prepare stmt4 from ' show variables like ''sql_mode'' ';
execute stmt4; execute stmt4;
# The output depends on the bdb being enabled and on the history prepare stmt4 from ' show engine myisam logs ';
# history (actions of the bdb engine).
# That is the reason why, we switch the output here off.
# (The real output will be tested in ps_6bdb.test)
--disable_result_log
prepare stmt4 from ' show engine bdb logs ';
execute stmt4; execute stmt4;
--enable_result_log
prepare stmt4 from ' show grants for user '; prepare stmt4 from ' show grants for user ';
prepare stmt4 from ' show create table t2 '; prepare stmt4 from ' show create table t2 ';
prepare stmt4 from ' show master status '; prepare stmt4 from ' show master status ';
......
...@@ -151,14 +151,14 @@ set global net_retry_count=10, session net_retry_count=10; ...@@ -151,14 +151,14 @@ set global net_retry_count=10, session net_retry_count=10;
set global net_buffer_length=1024, net_write_timeout=200, net_read_timeout=300; set global net_buffer_length=1024, net_write_timeout=200, net_read_timeout=300;
set session net_buffer_length=2048, net_write_timeout=500, net_read_timeout=600; set session net_buffer_length=2048, net_write_timeout=500, net_read_timeout=600;
show global variables like 'net_%'; show global variables like 'net_%';
select * from information_schema.global_variables where variable_name like 'net_%'; select * from information_schema.global_variables where variable_name like 'net_%' order by 1;
show session variables like 'net_%'; show session variables like 'net_%';
select * from information_schema.session_variables where variable_name like 'net_%'; select * from information_schema.session_variables where variable_name like 'net_%' order by 1;
set session net_buffer_length=8000, global net_read_timeout=900, net_write_timeout=1000; set session net_buffer_length=8000, global net_read_timeout=900, net_write_timeout=1000;
show global variables like 'net_%'; show global variables like 'net_%';
select * from information_schema.global_variables where variable_name like 'net_%'; select * from information_schema.global_variables where variable_name like 'net_%' order by 1;
show session variables like 'net_%'; show session variables like 'net_%';
select * from information_schema.session_variables where variable_name like 'net_%'; select * from information_schema.session_variables where variable_name like 'net_%' order by 1;
set net_buffer_length=1; set net_buffer_length=1;
show variables like 'net_buffer_length'; show variables like 'net_buffer_length';
select * from information_schema.session_variables where variable_name like 'net_buffer_length'; select * from information_schema.session_variables where variable_name like 'net_buffer_length';
...@@ -175,7 +175,7 @@ set @@rand_seed1=10000000,@@rand_seed2=1000000; ...@@ -175,7 +175,7 @@ set @@rand_seed1=10000000,@@rand_seed2=1000000;
select ROUND(RAND(),5); select ROUND(RAND(),5);
show variables like '%alloc%'; show variables like '%alloc%';
select * from information_schema.session_variables where variable_name like '%alloc%'; select * from information_schema.session_variables where variable_name like '%alloc%' order by 1;
set @@range_alloc_block_size=1024*16; set @@range_alloc_block_size=1024*16;
set @@query_alloc_block_size=1024*17+2; set @@query_alloc_block_size=1024*17+2;
set @@query_prealloc_size=1024*18; set @@query_prealloc_size=1024*18;
...@@ -183,12 +183,12 @@ set @@transaction_alloc_block_size=1024*20-1; ...@@ -183,12 +183,12 @@ set @@transaction_alloc_block_size=1024*20-1;
set @@transaction_prealloc_size=1024*21-1; set @@transaction_prealloc_size=1024*21-1;
select @@query_alloc_block_size; select @@query_alloc_block_size;
show variables like '%alloc%'; show variables like '%alloc%';
select * from information_schema.session_variables where variable_name like '%alloc%'; select * from information_schema.session_variables where variable_name like '%alloc%' order by 1;
set @@range_alloc_block_size=default; set @@range_alloc_block_size=default;
set @@query_alloc_block_size=default, @@query_prealloc_size=default; set @@query_alloc_block_size=default, @@query_prealloc_size=default;
set transaction_alloc_block_size=default, @@transaction_prealloc_size=default; set transaction_alloc_block_size=default, @@transaction_prealloc_size=default;
show variables like '%alloc%'; show variables like '%alloc%';
select * from information_schema.session_variables where variable_name like '%alloc%'; select * from information_schema.session_variables where variable_name like '%alloc%' order by 1;
# #
# Bug #10904 Illegal mix of collations between # Bug #10904 Illegal mix of collations between
...@@ -669,7 +669,7 @@ select @@ssl_ca, @@ssl_capath, @@ssl_cert, @@ssl_cipher, @@ssl_key; ...@@ -669,7 +669,7 @@ select @@ssl_ca, @@ssl_capath, @@ssl_cert, @@ssl_cipher, @@ssl_key;
--replace_column 2 # --replace_column 2 #
show variables like 'ssl%'; show variables like 'ssl%';
--replace_column 2 # --replace_column 2 #
select * from information_schema.session_variables where variable_name like 'ssl%'; select * from information_schema.session_variables where variable_name like 'ssl%' order by 1;
# #
# Bug #19616: make log_queries_not_using_indexes available in SHOW VARIABLES # Bug #19616: make log_queries_not_using_indexes available in SHOW VARIABLES
......
--loose-skip-ndb --loose-skip-plugin-ndbcluster
...@@ -26,9 +26,10 @@ ...@@ -26,9 +26,10 @@
Initiate dynamic array Initiate dynamic array
SYNOPSIS SYNOPSIS
init_dynamic_array() init_dynamic_array2()
array Pointer to an array array Pointer to an array
element_size Size of element element_size Size of element
init_buffer Initial buffer pointer
init_alloc Number of initial elements init_alloc Number of initial elements
alloc_increment Increment for adding new elements alloc_increment Increment for adding new elements
...@@ -36,14 +37,15 @@ ...@@ -36,14 +37,15 @@
init_dynamic_array() initiates array and allocate space for init_dynamic_array() initiates array and allocate space for
init_alloc eilements. init_alloc eilements.
Array is usable even if space allocation failed. Array is usable even if space allocation failed.
Static buffers must begin immediately after the array structure.
RETURN VALUE RETURN VALUE
TRUE my_malloc_ci() failed TRUE my_malloc_ci() failed
FALSE Ok FALSE Ok
*/ */
my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size, my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
uint init_alloc, void *init_buffer, uint init_alloc,
uint alloc_increment CALLER_INFO_PROTO) uint alloc_increment CALLER_INFO_PROTO)
{ {
DBUG_ENTER("init_dynamic_array"); DBUG_ENTER("init_dynamic_array");
...@@ -56,10 +58,14 @@ my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size, ...@@ -56,10 +58,14 @@ my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
if (!init_alloc) if (!init_alloc)
init_alloc=alloc_increment; init_alloc=alloc_increment;
else
init_buffer= 0;
array->elements=0; array->elements=0;
array->max_element=init_alloc; array->max_element=init_alloc;
array->alloc_increment=alloc_increment; array->alloc_increment=alloc_increment;
array->size_of_element=element_size; array->size_of_element=element_size;
if ((array->buffer= init_buffer))
DBUG_RETURN(FALSE);
if (!(array->buffer=(char*) my_malloc_ci(element_size*init_alloc,MYF(MY_WME)))) if (!(array->buffer=(char*) my_malloc_ci(element_size*init_alloc,MYF(MY_WME))))
{ {
array->max_element=0; array->max_element=0;
...@@ -68,6 +74,14 @@ my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size, ...@@ -68,6 +74,14 @@ my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
my_bool init_dynamic_array(DYNAMIC_ARRAY *array, uint element_size,
uint init_alloc,
uint alloc_increment CALLER_INFO_PROTO)
{
/* placeholder to preserve ABI */
return my_init_dynamic_array_ci(array, element_size, init_alloc,
alloc_increment);
}
/* /*
Insert element at the end of array. Allocate memory if needed. Insert element at the end of array. Allocate memory if needed.
...@@ -121,6 +135,21 @@ byte *alloc_dynamic(DYNAMIC_ARRAY *array) ...@@ -121,6 +135,21 @@ byte *alloc_dynamic(DYNAMIC_ARRAY *array)
if (array->elements == array->max_element) if (array->elements == array->max_element)
{ {
char *new_ptr; char *new_ptr;
if (array->buffer == (char *)(array + 1))
{
/*
In this senerio, the buffer is statically preallocated,
so we have to create an all-new malloc since we overflowed
*/
if (!(new_ptr= (char *) my_malloc((array->max_element+
array->alloc_increment) *
array->size_of_element,
MYF(MY_WME))))
return 0;
memcpy(new_ptr, array->buffer,
array->elements * array->size_of_element);
}
else
if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+ if (!(new_ptr=(char*) my_realloc(array->buffer,(array->max_element+
array->alloc_increment)* array->alloc_increment)*
array->size_of_element, array->size_of_element,
...@@ -180,6 +209,20 @@ my_bool set_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx) ...@@ -180,6 +209,20 @@ my_bool set_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
char *new_ptr; char *new_ptr;
size=(idx+array->alloc_increment)/array->alloc_increment; size=(idx+array->alloc_increment)/array->alloc_increment;
size*= array->alloc_increment; size*= array->alloc_increment;
if (array->buffer == (char *)(array + 1))
{
/*
In this senerio, the buffer is statically preallocated,
so we have to create an all-new malloc since we overflowed
*/
if (!(new_ptr= (char *) my_malloc(size *
array->size_of_element,
MYF(MY_WME))))
return 0;
memcpy(new_ptr, array->buffer,
array->elements * array->size_of_element);
}
else
if (!(new_ptr=(char*) my_realloc(array->buffer,size* if (!(new_ptr=(char*) my_realloc(array->buffer,size*
array->size_of_element, array->size_of_element,
MYF(MY_WME | MY_ALLOW_ZERO_PTR)))) MYF(MY_WME | MY_ALLOW_ZERO_PTR))))
...@@ -230,6 +273,12 @@ void get_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx) ...@@ -230,6 +273,12 @@ void get_dynamic(DYNAMIC_ARRAY *array, gptr element, uint idx)
void delete_dynamic(DYNAMIC_ARRAY *array) void delete_dynamic(DYNAMIC_ARRAY *array)
{ {
/*
Just mark as empty if we are using a static buffer
*/
if (array->buffer == (char *)(array + 1))
array->elements= 0;
else
if (array->buffer) if (array->buffer)
{ {
my_free(array->buffer,MYF(MY_WME)); my_free(array->buffer,MYF(MY_WME));
...@@ -269,6 +318,12 @@ void freeze_size(DYNAMIC_ARRAY *array) ...@@ -269,6 +318,12 @@ void freeze_size(DYNAMIC_ARRAY *array)
{ {
uint elements=max(array->elements,1); uint elements=max(array->elements,1);
/*
Do nothing if we are using a static buffer
*/
if (array->buffer == (char *)(array + 1))
return;
if (array->buffer && array->max_element != elements) if (array->buffer && array->max_element != elements)
{ {
array->buffer=(char*) my_realloc(array->buffer, array->buffer=(char*) my_realloc(array->buffer,
......
...@@ -315,6 +315,10 @@ my_bool my_hash_insert(HASH *info,const byte *record) ...@@ -315,6 +315,10 @@ my_bool my_hash_insert(HASH *info,const byte *record)
LINT_INIT(gpos); LINT_INIT(gpos2); LINT_INIT(gpos); LINT_INIT(gpos2);
LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2); LINT_INIT(ptr_to_rec); LINT_INIT(ptr_to_rec2);
if (HASH_UNIQUE & info->flags &&
hash_search(info, hash_key(info, record, &idx, 1), idx))
return(TRUE); /* Duplicate entry */
flag=0; flag=0;
if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array))) if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
return(TRUE); /* No more memory */ return(TRUE); /* No more memory */
...@@ -530,6 +534,19 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length) ...@@ -530,6 +534,19 @@ my_bool hash_update(HASH *hash,byte *record,byte *old_key,uint old_key_length)
uint idx,new_index,new_pos_index,blength,records,empty; uint idx,new_index,new_pos_index,blength,records,empty;
HASH_LINK org_link,*data,*previous,*pos; HASH_LINK org_link,*data,*previous,*pos;
DBUG_ENTER("hash_update"); DBUG_ENTER("hash_update");
if (HASH_UNIQUE & hash->flags)
{
HASH_SEARCH_STATE state;
byte *found, *new_key= hash_key(hash, record, &idx, 1);
if ((found= hash_first(hash, new_key, idx, &state)))
do
{
if (found != record)
DBUG_RETURN(1); /* Duplicate entry */
}
while ((found= hash_next(hash, new_key, idx, &state)));
}
data=dynamic_element(&hash->array,0,HASH_LINK*); data=dynamic_element(&hash->array,0,HASH_LINK*);
blength=hash->blength; records=hash->records; blength=hash->blength; records=hash->records;
......
...@@ -58,6 +58,13 @@ char *disabled_my_option= (char*) "0"; ...@@ -58,6 +58,13 @@ char *disabled_my_option= (char*) "0";
my_bool my_getopt_print_errors= 1; my_bool my_getopt_print_errors= 1;
/*
This is a flag that can be set in client programs. 1 means that
my_getopt will skip over options it does not know how to handle.
*/
my_bool my_getopt_skip_unknown= 0;
static void default_reporter(enum loglevel level, static void default_reporter(enum loglevel level,
const char *format, ...) const char *format, ...)
{ {
...@@ -110,6 +117,7 @@ int handle_options(int *argc, char ***argv, ...@@ -110,6 +117,7 @@ int handle_options(int *argc, char ***argv,
for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++) for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
{ {
char **first= pos;
char *cur_arg= *pos; char *cur_arg= *pos;
if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */ if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
{ {
...@@ -259,6 +267,19 @@ int handle_options(int *argc, char ***argv, ...@@ -259,6 +267,19 @@ int handle_options(int *argc, char ***argv,
} }
if (!opt_found) if (!opt_found)
{ {
if (my_getopt_skip_unknown)
{
/*
preserve all the components of this unknown option, this may
occurr when the user provides options like: "-O foo" or
"--set-variable foo" (note that theres a space in there)
Generally, these kind of options are to be avoided
*/
do {
(*argv)[argvpos++]= *first++;
} while (first <= pos);
continue;
}
if (must_be_var) if (must_be_var)
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
...@@ -596,6 +617,15 @@ static int setval(const struct my_option *opts, gptr *value, char *argument, ...@@ -596,6 +617,15 @@ static int setval(const struct my_option *opts, gptr *value, char *argument,
if (!(*((char**) result_pos)= my_strdup(argument, MYF(MY_WME)))) if (!(*((char**) result_pos)= my_strdup(argument, MYF(MY_WME))))
return EXIT_OUT_OF_MEMORY; return EXIT_OUT_OF_MEMORY;
break; break;
case GET_ENUM:
if (((*(int*)result_pos)= find_type(argument, opts->typelib, 2) - 1) < 0)
return EXIT_ARGUMENT_INVALID;
break;
case GET_SET:
*((ulonglong*)result_pos)= find_typeset(argument, opts->typelib, &err);
if (err)
return EXIT_ARGUMENT_INVALID;
break;
default: /* dummy default to avoid compiler warnings */ default: /* dummy default to avoid compiler warnings */
break; break;
} }
...@@ -788,6 +818,7 @@ static void init_one_value(const struct my_option *option, gptr *variable, ...@@ -788,6 +818,7 @@ static void init_one_value(const struct my_option *option, gptr *variable,
*((int*) variable)= (int) value; *((int*) variable)= (int) value;
break; break;
case GET_UINT: case GET_UINT:
case GET_ENUM:
*((uint*) variable)= (uint) value; *((uint*) variable)= (uint) value;
break; break;
case GET_LONG: case GET_LONG:
...@@ -800,6 +831,7 @@ static void init_one_value(const struct my_option *option, gptr *variable, ...@@ -800,6 +831,7 @@ static void init_one_value(const struct my_option *option, gptr *variable,
*((longlong*) variable)= (longlong) value; *((longlong*) variable)= (longlong) value;
break; break;
case GET_ULL: case GET_ULL:
case GET_SET:
*((ulonglong*) variable)= (ulonglong) value; *((ulonglong*) variable)= (ulonglong) value;
break; break;
default: /* dummy default to avoid compiler warnings */ default: /* dummy default to avoid compiler warnings */
...@@ -928,7 +960,8 @@ void my_print_help(const struct my_option *options) ...@@ -928,7 +960,8 @@ void my_print_help(const struct my_option *options)
void my_print_variables(const struct my_option *options) void my_print_variables(const struct my_option *options)
{ {
uint name_space= 34, length; uint name_space= 34, length, nr;
ulonglong bit, llvalue;
char buff[255]; char buff[255];
const struct my_option *optp; const struct my_option *optp;
...@@ -946,6 +979,21 @@ void my_print_variables(const struct my_option *options) ...@@ -946,6 +979,21 @@ void my_print_variables(const struct my_option *options)
for (; length < name_space; length++) for (; length < name_space; length++)
putchar(' '); putchar(' ');
switch ((optp->var_type & GET_TYPE_MASK)) { switch ((optp->var_type & GET_TYPE_MASK)) {
case GET_SET:
if (!(llvalue= *(ulonglong*) value))
printf("%s\n", "(No default value)");
else
for (nr= 0, bit= 1; llvalue && nr < optp->typelib->count; nr++, bit<<=1)
{
if (!(bit & llvalue))
continue;
llvalue&= ~bit;
printf( llvalue ? "%s," : "%s\n", get_type(optp->typelib, nr));
}
break;
case GET_ENUM:
printf("%s\n", get_type(optp->typelib, *(uint*) value));
break;
case GET_STR: case GET_STR:
case GET_STR_ALLOC: /* fall through */ case GET_STR_ALLOC: /* fall through */
printf("%s\n", *((char**) value) ? *((char**) value) : printf("%s\n", *((char**) value) ? *((char**) value) :
......
...@@ -120,6 +120,54 @@ const char *get_type(TYPELIB *typelib, uint nr) ...@@ -120,6 +120,54 @@ const char *get_type(TYPELIB *typelib, uint nr)
} }
static const char field_separator=',';
/*
Create an integer value to represent the supplied comma-seperated
string where each string in the TYPELIB denotes a bit position.
SYNOPSIS
find_typeset()
x string to decompose
lib TYPELIB (struct of pointer to values + count)
err index (not char position) of string element which was not
found or 0 if there was no error
RETURN
a integer representation of the supplied string
*/
my_ulonglong find_typeset(my_string x, TYPELIB *lib, int *err)
{
my_ulonglong result;
int find;
my_string i;
DBUG_ENTER("find_set");
DBUG_PRINT("enter",("x: '%s' lib: 0x%lx", x, (long) lib));
if (!lib->count)
{
DBUG_PRINT("exit",("no count"));
DBUG_RETURN(0);
}
result= 0;
*err= 0;
while (*x)
{
(*err)++;
i= x;
while (*x && *x != field_separator) x++;
if (*x)
*x++= 0;
if ((find= find_type(i, lib, 2) - 1) < 0)
DBUG_RETURN(0);
result|= (ULL(1) << find);
}
*err= 0;
DBUG_RETURN(result);
} /* find_set */
/* /*
Create a copy of a specified TYPELIB structure. Create a copy of a specified TYPELIB structure.
......
...@@ -2629,7 +2629,7 @@ int ha_ndbcluster::write_row(byte *record) ...@@ -2629,7 +2629,7 @@ int ha_ndbcluster::write_row(byte *record)
DBUG_RETURN(peek_res); DBUG_RETURN(peek_res);
} }
statistic_increment(thd->status_var.ha_write_count, &LOCK_status); ha_statistic_increment(&SSV::ha_write_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time(); table->timestamp_field->set_time();
...@@ -2849,7 +2849,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) ...@@ -2849,7 +2849,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
DBUG_RETURN(peek_res); DBUG_RETURN(peek_res);
} }
statistic_increment(thd->status_var.ha_update_count, &LOCK_status); ha_statistic_increment(&SSV::ha_update_count);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
{ {
table->timestamp_field->set_time(); table->timestamp_field->set_time();
...@@ -3016,7 +3016,7 @@ int ha_ndbcluster::delete_row(const byte *record) ...@@ -3016,7 +3016,7 @@ int ha_ndbcluster::delete_row(const byte *record)
DBUG_ENTER("delete_row"); DBUG_ENTER("delete_row");
m_write_op= TRUE; m_write_op= TRUE;
statistic_increment(thd->status_var.ha_delete_count,&LOCK_status); ha_statistic_increment(&SSV::ha_delete_count);
m_rows_changed++; m_rows_changed++;
if (m_use_partition_function && if (m_use_partition_function &&
...@@ -3372,7 +3372,7 @@ int ha_ndbcluster::index_read_idx(byte *buf, uint index_no, ...@@ -3372,7 +3372,7 @@ int ha_ndbcluster::index_read_idx(byte *buf, uint index_no,
const byte *key, uint key_len, const byte *key, uint key_len,
enum ha_rkey_function find_flag) enum ha_rkey_function find_flag)
{ {
statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status); ha_statistic_increment(&SSV::ha_read_key_count);
DBUG_ENTER("ha_ndbcluster::index_read_idx"); DBUG_ENTER("ha_ndbcluster::index_read_idx");
DBUG_PRINT("enter", ("index_no: %u, key_len: %u", index_no, key_len)); DBUG_PRINT("enter", ("index_no: %u, key_len: %u", index_no, key_len));
close_scan(); close_scan();
...@@ -3384,8 +3384,7 @@ int ha_ndbcluster::index_read_idx(byte *buf, uint index_no, ...@@ -3384,8 +3384,7 @@ int ha_ndbcluster::index_read_idx(byte *buf, uint index_no,
int ha_ndbcluster::index_next(byte *buf) int ha_ndbcluster::index_next(byte *buf)
{ {
DBUG_ENTER("ha_ndbcluster::index_next"); DBUG_ENTER("ha_ndbcluster::index_next");
statistic_increment(current_thd->status_var.ha_read_next_count, ha_statistic_increment(&SSV::ha_read_next_count);
&LOCK_status);
DBUG_RETURN(next_result(buf)); DBUG_RETURN(next_result(buf));
} }
...@@ -3393,8 +3392,7 @@ int ha_ndbcluster::index_next(byte *buf) ...@@ -3393,8 +3392,7 @@ int ha_ndbcluster::index_next(byte *buf)
int ha_ndbcluster::index_prev(byte *buf) int ha_ndbcluster::index_prev(byte *buf)
{ {
DBUG_ENTER("ha_ndbcluster::index_prev"); DBUG_ENTER("ha_ndbcluster::index_prev");
statistic_increment(current_thd->status_var.ha_read_prev_count, ha_statistic_increment(&SSV::ha_read_prev_count);
&LOCK_status);
DBUG_RETURN(next_result(buf)); DBUG_RETURN(next_result(buf));
} }
...@@ -3402,8 +3400,7 @@ int ha_ndbcluster::index_prev(byte *buf) ...@@ -3402,8 +3400,7 @@ int ha_ndbcluster::index_prev(byte *buf)
int ha_ndbcluster::index_first(byte *buf) int ha_ndbcluster::index_first(byte *buf)
{ {
DBUG_ENTER("ha_ndbcluster::index_first"); DBUG_ENTER("ha_ndbcluster::index_first");
statistic_increment(current_thd->status_var.ha_read_first_count, ha_statistic_increment(&SSV::ha_read_first_count);
&LOCK_status);
// Start the ordered index scan and fetch the first row // Start the ordered index scan and fetch the first row
// Only HA_READ_ORDER indexes get called by index_first // Only HA_READ_ORDER indexes get called by index_first
...@@ -3414,7 +3411,7 @@ int ha_ndbcluster::index_first(byte *buf) ...@@ -3414,7 +3411,7 @@ int ha_ndbcluster::index_first(byte *buf)
int ha_ndbcluster::index_last(byte *buf) int ha_ndbcluster::index_last(byte *buf)
{ {
DBUG_ENTER("ha_ndbcluster::index_last"); DBUG_ENTER("ha_ndbcluster::index_last");
statistic_increment(current_thd->status_var.ha_read_last_count,&LOCK_status); ha_statistic_increment(&SSV::ha_read_last_count);
DBUG_RETURN(ordered_index_scan(0, 0, TRUE, TRUE, buf, NULL)); DBUG_RETURN(ordered_index_scan(0, 0, TRUE, TRUE, buf, NULL));
} }
...@@ -3600,8 +3597,7 @@ int ha_ndbcluster::rnd_end() ...@@ -3600,8 +3597,7 @@ int ha_ndbcluster::rnd_end()
int ha_ndbcluster::rnd_next(byte *buf) int ha_ndbcluster::rnd_next(byte *buf)
{ {
DBUG_ENTER("rnd_next"); DBUG_ENTER("rnd_next");
statistic_increment(current_thd->status_var.ha_read_rnd_next_count, ha_statistic_increment(&SSV::ha_read_rnd_next_count);
&LOCK_status);
if (!m_active_cursor) if (!m_active_cursor)
DBUG_RETURN(full_table_scan(buf)); DBUG_RETURN(full_table_scan(buf));
...@@ -3619,8 +3615,7 @@ int ha_ndbcluster::rnd_next(byte *buf) ...@@ -3619,8 +3615,7 @@ int ha_ndbcluster::rnd_next(byte *buf)
int ha_ndbcluster::rnd_pos(byte *buf, byte *pos) int ha_ndbcluster::rnd_pos(byte *buf, byte *pos)
{ {
DBUG_ENTER("rnd_pos"); DBUG_ENTER("rnd_pos");
statistic_increment(current_thd->status_var.ha_read_rnd_count, ha_statistic_increment(&SSV::ha_read_rnd_count);
&LOCK_status);
// The primary key for the record is stored in pos // The primary key for the record is stored in pos
// Perform a pk_read using primary key "index" // Perform a pk_read using primary key "index"
{ {
...@@ -6743,7 +6738,7 @@ static int ndbcluster_init(void *p) ...@@ -6743,7 +6738,7 @@ static int ndbcluster_init(void *p)
{ {
handlerton *h= ndbcluster_hton; handlerton *h= ndbcluster_hton;
h->state= have_ndbcluster; h->state= SHOW_OPTION_YES;
h->db_type= DB_TYPE_NDBCLUSTER; h->db_type= DB_TYPE_NDBCLUSTER;
h->close_connection= ndbcluster_close_connection; h->close_connection= ndbcluster_close_connection;
h->commit= ndbcluster_commit; h->commit= ndbcluster_commit;
...@@ -6765,9 +6760,6 @@ static int ndbcluster_init(void *p) ...@@ -6765,9 +6760,6 @@ static int ndbcluster_init(void *p)
h->table_exists_in_engine= ndbcluster_table_exists_in_engine; h->table_exists_in_engine= ndbcluster_table_exists_in_engine;
} }
if (have_ndbcluster != SHOW_OPTION_YES)
DBUG_RETURN(0); // nothing else to do
// Initialize ndb interface // Initialize ndb interface
ndb_init_internal(); ndb_init_internal();
...@@ -6883,7 +6875,6 @@ static int ndbcluster_init(void *p) ...@@ -6883,7 +6875,6 @@ static int ndbcluster_init(void *p)
if (g_ndb_cluster_connection) if (g_ndb_cluster_connection)
delete g_ndb_cluster_connection; delete g_ndb_cluster_connection;
g_ndb_cluster_connection= NULL; g_ndb_cluster_connection= NULL;
have_ndbcluster= SHOW_OPTION_DISABLED; // If we couldn't use handler
ndbcluster_hton->state= SHOW_OPTION_DISABLED; // If we couldn't use handler ndbcluster_hton->state= SHOW_OPTION_DISABLED; // If we couldn't use handler
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -10220,10 +10211,6 @@ ndbcluster_show_status(handlerton *hton, THD* thd, stat_print_fn *stat_print, ...@@ -10220,10 +10211,6 @@ ndbcluster_show_status(handlerton *hton, THD* thd, stat_print_fn *stat_print,
uint buflen; uint buflen;
DBUG_ENTER("ndbcluster_show_status"); DBUG_ENTER("ndbcluster_show_status");
if (have_ndbcluster != SHOW_OPTION_YES)
{
DBUG_RETURN(FALSE);
}
if (stat_type != HA_ENGINE_STATUS) if (stat_type != HA_ENGINE_STATUS)
{ {
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
......
...@@ -1987,6 +1987,8 @@ bool ha_partition::create_handler_file(const char *name) ...@@ -1987,6 +1987,8 @@ bool ha_partition::create_handler_file(const char *name)
void ha_partition::clear_handler_file() void ha_partition::clear_handler_file()
{ {
if (m_engine_array)
plugin_unlock_list(NULL, m_engine_array, m_tot_parts);
my_free((char*) m_file_buffer, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) m_file_buffer, MYF(MY_ALLOW_ZERO_PTR));
my_free((char*) m_engine_array, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) m_engine_array, MYF(MY_ALLOW_ZERO_PTR));
m_file_buffer= NULL; m_file_buffer= NULL;
...@@ -2009,6 +2011,7 @@ bool ha_partition::create_handlers(MEM_ROOT *mem_root) ...@@ -2009,6 +2011,7 @@ bool ha_partition::create_handlers(MEM_ROOT *mem_root)
{ {
uint i; uint i;
uint alloc_len= (m_tot_parts + 1) * sizeof(handler*); uint alloc_len= (m_tot_parts + 1) * sizeof(handler*);
handlerton *hton0;
DBUG_ENTER("create_handlers"); DBUG_ENTER("create_handlers");
if (!(m_file= (handler **) alloc_root(mem_root, alloc_len))) if (!(m_file= (handler **) alloc_root(mem_root, alloc_len)))
...@@ -2017,19 +2020,21 @@ bool ha_partition::create_handlers(MEM_ROOT *mem_root) ...@@ -2017,19 +2020,21 @@ bool ha_partition::create_handlers(MEM_ROOT *mem_root)
bzero((char*) m_file, alloc_len); bzero((char*) m_file, alloc_len);
for (i= 0; i < m_tot_parts; i++) for (i= 0; i < m_tot_parts; i++)
{ {
handlerton *hton= plugin_data(m_engine_array[i], handlerton*);
if (!(m_file[i]= get_new_handler(table_share, mem_root, if (!(m_file[i]= get_new_handler(table_share, mem_root,
m_engine_array[i]))) hton)))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
DBUG_PRINT("info", ("engine_type: %u", m_engine_array[i]->db_type)); DBUG_PRINT("info", ("engine_type: %u", hton->db_type));
} }
/* For the moment we only support partition over the same table engine */ /* For the moment we only support partition over the same table engine */
if (m_engine_array[0] == myisam_hton) hton0= plugin_data(m_engine_array[0], handlerton*);
if (hton0 == myisam_hton)
{ {
DBUG_PRINT("info", ("MyISAM")); DBUG_PRINT("info", ("MyISAM"));
m_myisam= TRUE; m_myisam= TRUE;
} }
/* INNODB may not be compiled in... */ /* INNODB may not be compiled in... */
else if (ha_legacy_type(m_engine_array[0]) == DB_TYPE_INNODB) else if (ha_legacy_type(hton0) == DB_TYPE_INNODB)
{ {
DBUG_PRINT("info", ("InnoDB")); DBUG_PRINT("info", ("InnoDB"));
m_innodb= TRUE; m_innodb= TRUE;
...@@ -2160,8 +2165,7 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root) ...@@ -2160,8 +2165,7 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
m_tot_parts= uint4korr((file_buffer) + 8); m_tot_parts= uint4korr((file_buffer) + 8);
DBUG_PRINT("info", ("No of parts = %u", m_tot_parts)); DBUG_PRINT("info", ("No of parts = %u", m_tot_parts));
tot_partition_words= (m_tot_parts + 3) / 4; tot_partition_words= (m_tot_parts + 3) / 4;
if (!(engine_array= (handlerton **) my_malloc(m_tot_parts * sizeof(handlerton*),MYF(0)))) engine_array= (handlerton **) my_alloca(m_tot_parts * sizeof(handlerton*));
goto err2;
for (i= 0; i < m_tot_parts; i++) for (i= 0; i < m_tot_parts; i++)
engine_array[i]= ha_resolve_by_legacy_type(current_thd, engine_array[i]= ha_resolve_by_legacy_type(current_thd,
(enum legacy_db_type) (enum legacy_db_type)
...@@ -2174,7 +2178,14 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root) ...@@ -2174,7 +2178,14 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
VOID(my_close(file, MYF(0))); VOID(my_close(file, MYF(0)));
m_file_buffer= file_buffer; // Will be freed in clear_handler_file() m_file_buffer= file_buffer; // Will be freed in clear_handler_file()
m_name_buffer_ptr= name_buffer_ptr; m_name_buffer_ptr= name_buffer_ptr;
m_engine_array= engine_array;
if (!(m_engine_array= (plugin_ref*)
my_malloc(m_tot_parts * sizeof(plugin_ref), MYF(MY_WME))))
goto err2;
for (i= 0; i < m_tot_parts; i++)
m_engine_array[i]= ha_lock_engine(NULL, engine_array[i]);
if (!m_file && create_handlers(mem_root)) if (!m_file && create_handlers(mem_root))
{ {
clear_handler_file(); clear_handler_file();
......
...@@ -27,6 +27,7 @@ enum partition_keywords ...@@ -27,6 +27,7 @@ enum partition_keywords
The partition implements the minimum of what you will probably need. The partition implements the minimum of what you will probably need.
*/ */
#ifdef NOT_USED
typedef struct st_partition_share typedef struct st_partition_share
{ {
char *table_name; char *table_name;
...@@ -34,6 +35,7 @@ typedef struct st_partition_share ...@@ -34,6 +35,7 @@ typedef struct st_partition_share
pthread_mutex_t mutex; pthread_mutex_t mutex;
THR_LOCK lock; THR_LOCK lock;
} PARTITION_SHARE; } PARTITION_SHARE;
#endif
#define PARTITION_BYTES_IN_POS 2 #define PARTITION_BYTES_IN_POS 2
...@@ -54,7 +56,7 @@ class ha_partition :public handler ...@@ -54,7 +56,7 @@ class ha_partition :public handler
uint m_open_test_lock; // Open test_if_locked uint m_open_test_lock; // Open test_if_locked
char *m_file_buffer; // Buffer with names char *m_file_buffer; // Buffer with names
char *m_name_buffer_ptr; // Pointer to first partition name char *m_name_buffer_ptr; // Pointer to first partition name
handlerton **m_engine_array; // Array of types of the handlers plugin_ref *m_engine_array; // Array of types of the handlers
handler **m_file; // Array of references to handler inst. handler **m_file; // Array of references to handler inst.
uint m_file_tot_parts; // Debug uint m_file_tot_parts; // Debug
handler **m_new_file; // Array of references to new handlers handler **m_new_file; // Array of references to new handlers
...@@ -130,7 +132,9 @@ class ha_partition :public handler ...@@ -130,7 +132,9 @@ class ha_partition :public handler
Variables for lock structures. Variables for lock structures.
*/ */
THR_LOCK_DATA lock; /* MySQL lock */ THR_LOCK_DATA lock; /* MySQL lock */
#ifdef NOT_USED
PARTITION_SHARE *share; /* Shared lock info */ PARTITION_SHARE *share; /* Shared lock info */
#endif
public: public:
virtual void set_part_info(partition_info *part_info) virtual void set_part_info(partition_info *part_info)
......
This diff is collapsed.
...@@ -876,6 +876,8 @@ class ha_statistics ...@@ -876,6 +876,8 @@ class ha_statistics
class handler :public Sql_alloc class handler :public Sql_alloc
{ {
friend class ha_partition; friend class ha_partition;
friend int ha_delete_table(THD*,handlerton*,const char*,const char*,
const char*,bool);
protected: protected:
struct st_table_share *table_share; /* The table definition */ struct st_table_share *table_share; /* The table definition */
...@@ -894,7 +896,12 @@ class handler :public Sql_alloc ...@@ -894,7 +896,12 @@ class handler :public Sql_alloc
virtual int rnd_init(bool scan) =0; virtual int rnd_init(bool scan) =0;
virtual int rnd_end() { return 0; } virtual int rnd_end() { return 0; }
virtual ulonglong table_flags(void) const =0; virtual ulonglong table_flags(void) const =0;
void ha_statistic_increment(ulong SSV::*offset) const; void ha_statistic_increment(ulong SSV::*offset) const;
enum enum_tx_isolation ha_tx_isolation(void) const;
uint ha_sql_command(void) const;
void **ha_data(void) const;
THD *ha_thd(void) const;
ha_rows estimation_rows_to_insert; ha_rows estimation_rows_to_insert;
virtual void start_bulk_insert(ha_rows rows) {} virtual void start_bulk_insert(ha_rows rows) {}
...@@ -1626,9 +1633,9 @@ extern ulong total_ha, total_ha_2pc; ...@@ -1626,9 +1633,9 @@ extern ulong total_ha, total_ha_2pc;
/* lookups */ /* lookups */
handlerton *ha_default_handlerton(THD *thd); handlerton *ha_default_handlerton(THD *thd);
handlerton *ha_resolve_by_name(THD *thd, const LEX_STRING *name); plugin_ref ha_resolve_by_name(THD *thd, const LEX_STRING *name);
plugin_ref ha_lock_engine(THD *thd, handlerton *hton);
handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type); handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type);
const char *ha_get_storage_engine(enum legacy_db_type db_type);
handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc, handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
handlerton *db_type); handlerton *db_type);
handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type, handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
......
...@@ -4887,7 +4887,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, ...@@ -4887,7 +4887,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
component_name= &component; // Empty string component_name= &component; // Empty string
} }
if (!(var= find_sys_var(base_name->str, base_name->length))) if (!(var= find_sys_var(thd, base_name->str, base_name->length)))
return 0; return 0;
if (component.str) if (component.str)
{ {
......
...@@ -2469,7 +2469,7 @@ bool Item_sum_count_distinct::setup(THD *thd) ...@@ -2469,7 +2469,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
table->no_rows=1; table->no_rows=1;
if (table->s->db_type == heap_hton) if (table->s->db_type() == heap_hton)
{ {
/* /*
No blobs, otherwise it would have been MyISAM: set up a compare No blobs, otherwise it would have been MyISAM: set up a compare
......
...@@ -546,11 +546,6 @@ inline THD *_current_thd(void) ...@@ -546,11 +546,6 @@ inline THD *_current_thd(void)
} }
#define current_thd _current_thd() #define current_thd _current_thd()
/* below functions are required for plugins as THD class is opaque */
my_bool thd_in_lock_tables(const THD *thd);
my_bool thd_tablespace_op(const THD *thd);
const char *thd_proc_info(THD *thd, const char *info);
void **thd_ha_data(const THD *thd, const struct handlerton *hton);
/* /*
External variables External variables
...@@ -1098,6 +1093,7 @@ int add_status_vars(SHOW_VAR *list); ...@@ -1098,6 +1093,7 @@ int add_status_vars(SHOW_VAR *list);
void remove_status_vars(SHOW_VAR *list); void remove_status_vars(SHOW_VAR *list);
void init_status_vars(); void init_status_vars();
void free_status_vars(); void free_status_vars();
void reset_status_vars();
/* information schema */ /* information schema */
extern LEX_STRING information_schema_name; extern LEX_STRING information_schema_name;
...@@ -1659,6 +1655,7 @@ extern pthread_mutex_t LOCK_server_started; ...@@ -1659,6 +1655,7 @@ extern pthread_mutex_t LOCK_server_started;
extern pthread_cond_t COND_server_started; extern pthread_cond_t COND_server_started;
extern int mysqld_server_started; extern int mysqld_server_started;
extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave; extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
extern rw_lock_t LOCK_system_variables_hash;
extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
extern pthread_cond_t COND_global_read_lock; extern pthread_cond_t COND_global_read_lock;
extern pthread_attr_t connection_attrib; extern pthread_attr_t connection_attrib;
...@@ -1667,7 +1664,7 @@ extern I_List<NAMED_LIST> key_caches; ...@@ -1667,7 +1664,7 @@ extern I_List<NAMED_LIST> key_caches;
extern MY_BITMAP temp_pool; extern MY_BITMAP temp_pool;
extern String my_empty_string; extern String my_empty_string;
extern const String my_null_string; extern const String my_null_string;
extern SHOW_VAR init_vars[], status_vars[], internal_vars[]; extern SHOW_VAR status_vars[];
extern struct system_variables global_system_variables; extern struct system_variables global_system_variables;
extern struct system_variables max_system_variables; extern struct system_variables max_system_variables;
extern struct system_status_var global_status_var; extern struct system_status_var global_status_var;
...@@ -1690,11 +1687,6 @@ extern TYPELIB log_output_typelib; ...@@ -1690,11 +1687,6 @@ extern TYPELIB log_output_typelib;
/* optional things, have_* variables */ /* optional things, have_* variables */
extern SHOW_COMP_OPTION have_innodb;
extern SHOW_COMP_OPTION have_csv_db;
extern SHOW_COMP_OPTION have_ndbcluster;
extern SHOW_COMP_OPTION have_partition_db;
extern handlerton *partition_hton; extern handlerton *partition_hton;
extern handlerton *myisam_hton; extern handlerton *myisam_hton;
extern handlerton *heap_hton; extern handlerton *heap_hton;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -868,7 +868,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) ...@@ -868,7 +868,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
/* If it is a temporary table, close and regenerate it */ /* If it is a temporary table, close and regenerate it */
if (!dont_send_ok && (table= find_temporary_table(thd, table_list))) if (!dont_send_ok && (table= find_temporary_table(thd, table_list)))
{ {
handlerton *table_type= table->s->db_type; handlerton *table_type= table->s->db_type();
TABLE_SHARE *share= table->s; TABLE_SHARE *share= table->s;
if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE)) if (!ha_check_storage_engine_flag(table_type, HTON_CAN_RECREATE))
goto trunc_by_del; goto trunc_by_del;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment