Commit b64060f7 authored by baker@bk-internal.mysql.com's avatar baker@bk-internal.mysql.com

Merge bk-internal.mysql.com:/data0/bk/mysql-5.1

into  bk-internal.mysql.com:/data0/bk/mysql-5.1-arch
parents 4fd3b03e 08e93132
......@@ -29,7 +29,8 @@
#define MYSQL_STORAGE_ENGINE_PLUGIN 1 /* Storage Engine */
#define MYSQL_FTPARSER_PLUGIN 2 /* Full-text parser plugin */
#define MYSQL_DAEMON_PLUGIN 3 /* The daemon/raw plugin type */
#define MYSQL_MAX_PLUGIN_TYPE_NUM 4 /* The number of plugin types */
#define MYSQL_INFORMATION_SCHEMA_PLUGIN 4 /* The I_S plugin type */
#define MYSQL_MAX_PLUGIN_TYPE_NUM 5 /* The number of plugin types */
/* We use the following strings to define licenses for plugins */
#define PLUGIN_LICENSE_PROPRIETARY 0
......@@ -302,6 +303,13 @@ struct st_mysql_ftparser
/* handlertons of different MySQL releases are incompatible */
#define MYSQL_DAEMON_INTERFACE_VERSION (MYSQL_VERSION_ID << 8)
/*************************************************************************
API for I_S plugin. (MYSQL_INFORMATION_SCHEMA_PLUGIN)
*/
/* handlertons of different MySQL releases are incompatible */
#define MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION (MYSQL_VERSION_ID << 8)
/*************************************************************************
API for Storage Engine plugin. (MYSQL_STORAGE_ENGINE_PLUGIN)
*/
......@@ -330,5 +338,15 @@ struct st_mysql_daemon
int interface_version;
};
/*
Here we define only the descriptor structure, that is referred from
st_mysql_plugin.
*/
struct st_mysql_information_schema
{
int interface_version;
};
#endif
drop table if exists t1,t2,t3,t4,t5;
DROP TABLE if exists t1,t2,t3,t4,t5,t6;
SET storage_engine=ARCHIVE;
CREATE TABLE t1 (
Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL,
Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL
......@@ -184,7 +185,7 @@ fld1 fld3
250503 heaving
250504 population
250505 bomb
create table t3 engine=archive select * FROM t2;
CREATE TABLE t3 engine=archive select * FROM t2;
select * FROM t3 where fld3='bonfire';
auto fld1 companynr fld3 fld4 fld5 fld6
1191 068504 00 bonfire corresponds positively
......@@ -12358,7 +12359,7 @@ CREATE TABLE `t5` (
`a` int(11) NOT NULL auto_increment,
b char(12),
PRIMARY KEY (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1;
) DEFAULT CHARSET=latin1;
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
......@@ -12366,6 +12367,7 @@ INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (32, "foo");
INSERT INTO t5 VALUES (23, "foo");
ERROR 23000: Can't write; duplicate key in table 't5'
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (3, "foo");
......@@ -12379,7 +12381,6 @@ a b
4 foo
5 foo
32 foo
23 foo
33 foo
34 foo
35 foo
......@@ -12391,7 +12392,7 @@ CREATE TABLE `t5` (
`a` int(11) NOT NULL auto_increment,
b char(12),
KEY (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1 AUTO_INCREMENT=5;
) DEFAULT CHARSET=latin1 AUTO_INCREMENT=5;
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
......@@ -12443,7 +12444,7 @@ CREATE TABLE `t5` (
`a` int(11) NOT NULL auto_increment,
b blob(12),
KEY (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1;
) DEFAULT CHARSET=latin1;
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "We the people");
INSERT INTO t5 VALUES (NULL, "in order to form a more pefect union");
......@@ -12496,7 +12497,7 @@ CREATE TABLE `t5` (
b blob(12),
c blob(12),
KEY (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1;
) DEFAULT CHARSET=latin1;
INSERT INTO t5 VALUES (NULL, "foo", "grok this!");
INSERT INTO t5 VALUES (NULL, "We the people", NULL);
INSERT INTO t5 VALUES (NULL, "in order to form a more peefect union", "secure the blessing of liberty");
......@@ -12545,8 +12546,8 @@ SELECT c FROM t5 WHERE a IN (32, 23, 5);
c
NULL
posterity
drop table t1;
create table t1 (v varchar(32));
DROP TABLE t1;
CREATE TABLE t1 (v varchar(32)) ;
insert into t1 values ('def'),('abc'),('hij'),('3r4f');
select * from t1;
v
......@@ -12554,68 +12555,34 @@ def
abc
hij
3r4f
alter table t1 change v v2 varchar(32);
ALTER TABLE t1 change v v2 varchar(32);
select * from t1;
v2
def
abc
hij
3r4f
alter table t1 change v2 v varchar(64);
ALTER TABLE t1 change v2 v varchar(64);
select * from t1;
v
def
abc
hij
3r4f
update t1 set v = 'lmn' where v = 'hij';
select * from t1;
v
def
abc
lmn
3r4f
alter table t1 add i int auto_increment not null primary key first;
ALTER TABLE t1 add i int auto_increment not null primary key first;
select * from t1;
i v
1 def
2 abc
3 lmn
4 3r4f
update t1 set i=5 where i=3;
select * from t1;
i v
1 def
2 abc
5 lmn
4 3r4f
alter table t1 change i i bigint;
select * from t1;
i v
1 def
2 abc
5 lmn
4 3r4f
alter table t1 add unique key (i, v);
select * from t1 where i between 2 and 4 and v in ('def','3r4f','lmn');
i v
3 hij
4 3r4f
alter table t1 data directory="$MYSQLTEST_VARDIR/tmp";
Warnings:
Warning 0 DATA DIRECTORY option ignored
select * from t1;
i v
1 def
2 abc
4 3r4f
5 lmn
DROP TABLE t5;
CREATE TABLE `t5` (
`a` int(11) NOT NULL auto_increment,
b varchar(250),
c varchar(800),
KEY (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1;
) DEFAULT CHARSET=latin1;
INSERT INTO t5 VALUES (NULL, "foo", "grok this!");
INSERT INTO t5 VALUES (NULL, "We the people", NULL);
INSERT INTO t5 VALUES (NULL, "in order to form a more peefect union", "secure the blessing of liberty");
......@@ -12636,4 +12603,66 @@ a b c
23 provide for the common defense posterity
33 promote the general welfare do ordain
34 abcdeghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyz do ordain
drop table t1, t2, t4, t5;
CREATE TABLE `t6` (
`a` int(11) NOT NULL auto_increment,
b blob(12),
c int,
KEY (`a`)
) DEFAULT CHARSET=latin1;
SELECT * FROM t6;
a b c
INSERT INTO t6 VALUES (NULL, "foo", NULL);
INSERT INTO t6 VALUES (NULL, "We the people", 5);
INSERT INTO t6 VALUES (NULL, "in order to form a more pefect union", 9);
INSERT INTO t6 VALUES (NULL, "establish justice", NULL);
INSERT INTO t6 VALUES (NULL, NULL, NULL);
INSERT INTO t6 VALUES (32, "ensure domestic tranquility", NULL);
INSERT INTO t6 VALUES (23, "provide for the common defense", 30);
INSERT INTO t6 VALUES (NULL, "fo fooo", 70);
INSERT INTO t6 VALUES (NULL, NULL, 98);
INSERT INTO t6 VALUES (NULL, "promote the general welfare", 50);
SELECT * FROM t6;
a b c
1 foo NULL
2 We the people 5
3 in order to form a more pefect union 9
4 establish justice NULL
5 NULL NULL
32 ensure domestic tranquility NULL
23 provide for the common defense 30
33 fo fooo 70
34 NULL 98
35 promote the general welfare 50
SELECT * FROM t6 ORDER BY a;
a b c
1 foo NULL
2 We the people 5
3 in order to form a more pefect union 9
4 establish justice NULL
5 NULL NULL
23 provide for the common defense 30
32 ensure domestic tranquility NULL
33 fo fooo 70
34 NULL 98
35 promote the general welfare 50
SELECT * FROM t6 ORDER BY a DESC;
a b c
35 promote the general welfare 50
34 NULL 98
33 fo fooo 70
32 ensure domestic tranquility NULL
23 provide for the common defense 30
5 NULL NULL
4 establish justice NULL
3 in order to form a more pefect union 9
2 We the people 5
1 foo NULL
SHOW CREATE TABLE t6;
Table Create Table
t6 CREATE TABLE `t6` (
`a` int(11) NOT NULL AUTO_INCREMENT,
`b` tinyblob,
`c` int(11) DEFAULT NULL,
KEY `a` (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1
DROP TABLE t1, t2, t4, t5, t6;
......@@ -6,9 +6,11 @@
-- source include/have_binlog_format_mixed_or_statement.inc
--disable_warnings
drop table if exists t1,t2,t3,t4,t5;
DROP TABLE if exists t1,t2,t3,t4,t5,t6;
--enable_warnings
SET storage_engine=ARCHIVE;
CREATE TABLE t1 (
Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL,
Varor_period smallint(4) unsigned DEFAULT '0' NOT NULL
......@@ -1294,7 +1296,7 @@ select fld1,fld3 FROM t2 where fld1 like "25050_";
#
# Test rename of table
#
create table t3 engine=archive select * FROM t2;
CREATE TABLE t3 engine=archive select * FROM t2;
select * FROM t3 where fld3='bonfire';
select count(*) FROM t3;
# Clean up path in error message
......@@ -1356,7 +1358,7 @@ while (`SELECT COUNT(auto)!=1214 FROM t2`)
}
SELECT COUNT(auto) FROM t2;
# Adding test for alter table
# Adding test for ALTER TABLE
ALTER TABLE t2 DROP COLUMN fld6;
SHOW CREATE TABLE t2;
SELECT * FROM t2;
......@@ -1369,7 +1371,7 @@ CREATE TABLE `t5` (
`a` int(11) NOT NULL auto_increment,
b char(12),
PRIMARY KEY (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1;
) DEFAULT CHARSET=latin1;
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
......@@ -1377,6 +1379,7 @@ INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (32, "foo");
--error 1022
INSERT INTO t5 VALUES (23, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
......@@ -1393,7 +1396,7 @@ CREATE TABLE `t5` (
`a` int(11) NOT NULL auto_increment,
b char(12),
KEY (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1 AUTO_INCREMENT=5;
) DEFAULT CHARSET=latin1 AUTO_INCREMENT=5;
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "foo");
......@@ -1419,7 +1422,7 @@ CREATE TABLE `t5` (
`a` int(11) NOT NULL auto_increment,
b blob(12),
KEY (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1;
) DEFAULT CHARSET=latin1;
INSERT INTO t5 VALUES (NULL, "foo");
INSERT INTO t5 VALUES (NULL, "We the people");
......@@ -1447,7 +1450,7 @@ CREATE TABLE `t5` (
b blob(12),
c blob(12),
KEY (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1;
) DEFAULT CHARSET=latin1;
INSERT INTO t5 VALUES (NULL, "foo", "grok this!");
INSERT INTO t5 VALUES (NULL, "We the people", NULL);
......@@ -1464,35 +1467,24 @@ SELECT c FROM t5;
SELECT c FROM t5 WHERE a =3;
SELECT c FROM t5 WHERE a IN (32, 23, 5);
# Adding this in case someone tries to add fast alter table and doesn't tes
# Adding this in case someone tries to add fast ALTER TABLE and doesn't tes
# it.
# Some additional tests for new, faster alter table. Note that most of the
# whole alter table code is being tested all around the test suite already.
# Some additional tests for new, faster ALTER TABLE. Note that most of the
# whole ALTER TABLE code is being tested all around the test suite already.
#
drop table t1;
create table t1 (v varchar(32));
DROP TABLE t1;
CREATE TABLE t1 (v varchar(32)) ;
insert into t1 values ('def'),('abc'),('hij'),('3r4f');
select * from t1;
# Fast alter, no copy performed
alter table t1 change v v2 varchar(32);
ALTER TABLE t1 change v v2 varchar(32);
select * from t1;
# Fast alter, no copy performed
alter table t1 change v2 v varchar(64);
select * from t1;
update t1 set v = 'lmn' where v = 'hij';
select * from t1;
# Regular alter table
alter table t1 add i int auto_increment not null primary key first;
ALTER TABLE t1 change v2 v varchar(64);
select * from t1;
update t1 set i=5 where i=3;
select * from t1;
alter table t1 change i i bigint;
select * from t1;
alter table t1 add unique key (i, v);
select * from t1 where i between 2 and 4 and v in ('def','3r4f','lmn');
alter table t1 data directory="$MYSQLTEST_VARDIR/tmp";
# Regular ALTER TABLE
ALTER TABLE t1 add i int auto_increment not null primary key first;
select * from t1;
# Testing cleared row key
......@@ -1503,7 +1495,7 @@ CREATE TABLE `t5` (
b varchar(250),
c varchar(800),
KEY (`a`)
) ENGINE=ARCHIVE DEFAULT CHARSET=latin1;
) DEFAULT CHARSET=latin1;
INSERT INTO t5 VALUES (NULL, "foo", "grok this!");
INSERT INTO t5 VALUES (NULL, "We the people", NULL);
......@@ -1516,11 +1508,35 @@ INSERT INTO t5 VALUES (NULL, "abcdeghijklmnopqrstuvwxyzabcdeghijklmnopqrstuvwxyz
SELECT * FROM t5;
CREATE TABLE `t6` (
`a` int(11) NOT NULL auto_increment,
b blob(12),
c int,
KEY (`a`)
) DEFAULT CHARSET=latin1;
SELECT * FROM t6;
INSERT INTO t6 VALUES (NULL, "foo", NULL);
INSERT INTO t6 VALUES (NULL, "We the people", 5);
INSERT INTO t6 VALUES (NULL, "in order to form a more pefect union", 9);
INSERT INTO t6 VALUES (NULL, "establish justice", NULL);
INSERT INTO t6 VALUES (NULL, NULL, NULL);
INSERT INTO t6 VALUES (32, "ensure domestic tranquility", NULL);
INSERT INTO t6 VALUES (23, "provide for the common defense", 30);
INSERT INTO t6 VALUES (NULL, "fo fooo", 70);
INSERT INTO t6 VALUES (NULL, NULL, 98);
INSERT INTO t6 VALUES (NULL, "promote the general welfare", 50);
SELECT * FROM t6;
SELECT * FROM t6 ORDER BY a;
SELECT * FROM t6 ORDER BY a DESC;
SHOW CREATE TABLE t6;
#
# Cleanup, test is over
#
--disable_warnings
drop table t1, t2, t4, t5;
DROP TABLE t1, t2, t4, t5, t6;
--enable_warnings
......@@ -19,18 +19,20 @@ MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
MYSQLLIBdir= $(pkglibdir)
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include \
-I$(srcdir)
-I$(top_srcdir)/regex \
-I$(top_srcdir)/sql \
-I$(srcdir) @ZLIB_INCLUDES@
EXTRA_LTLIBRARIES = libdaemon_example.la
pkglib_LTLIBRARIES = @plugin_daemon_example_shared_target@
libdaemon_example_la_LDFLAGS = -module -rpath $(MYSQLLIBdir)
libdaemon_example_la_CXXFLAGS= $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN
libdaemon_example_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN
libdaemon_example_la_SOURCES = daemon_example.c
libdaemon_example_la_SOURCES = daemon_example.cc
EXTRA_LIBRARIES = libdaemon_example.a
noinst_LIBRARIES = @plugin_daemon_example_static_target@
libdaemon_example_a_CXXFLAGS = $(AM_CFLAGS)
libdaemon_example_a_CFLAGS = $(AM_CFLAGS)
libdaemon_example_a_SOURCES= daemon_example.c
libdaemon_example_a_SOURCES= daemon_example.cc
......@@ -13,10 +13,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include <mysql_priv.h>
#include <stdlib.h>
#include <ctype.h>
#include <mysql_version.h>
#include <mysql/plugin.h>
#include <my_global.h>
#include <my_dir.h>
/*
#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8)
......@@ -24,7 +27,44 @@
#endif
*/
#define HEART_STRING_BUFFER 100
struct mysql_heartbeat_context
{
pthread_t heartbeat_thread;
File heartbeat_file;
};
pthread_handler_t mysql_heartbeat(void *p)
{
DBUG_ENTER("mysql_heartbeat");
struct mysql_heartbeat_context *con= (struct mysql_heartbeat_context *)p;
char buffer[HEART_STRING_BUFFER];
unsigned int x= 0;
time_t result;
struct tm tm_tmp;
while(1)
{
sleep(5);
result= time(NULL);
localtime_r(&result, &tm_tmp);
my_snprintf(buffer, sizeof(buffer),
"Heartbeat at %02d%02d%02d %2d:%02d:%02d\n",
tm_tmp.tm_year % 100,
tm_tmp.tm_mon+1,
tm_tmp.tm_mday,
tm_tmp.tm_hour,
tm_tmp.tm_min,
tm_tmp.tm_sec);
my_write(con->heartbeat_file, buffer, strlen(buffer), MYF(0));
x++;
}
DBUG_RETURN(0);
}
/*
Initialize the daemon example at server start or plugin installation.
......@@ -33,7 +73,7 @@
daemon_example_plugin_init()
DESCRIPTION
Does nothing.
Starts up heartbeatbeat thread
RETURN VALUE
0 success
......@@ -42,7 +82,51 @@
static int daemon_example_plugin_init(void *p)
{
return(0);
DBUG_ENTER("daemon_example_plugin_init");
struct mysql_heartbeat_context *con;
pthread_attr_t attr; /* Thread attributes */
char heartbeat_filename[FN_REFLEN];
char buffer[HEART_STRING_BUFFER];
time_t result= time(NULL);
struct tm tm_tmp;
struct st_plugin_int *plugin= (struct st_plugin_int *)p;
con= (struct mysql_heartbeat_context *)my_malloc(sizeof(struct mysql_heartbeat_context), MYF(0));
fn_format(heartbeat_filename, "mysql-heartbeat", "", ".log", MY_REPLACE_EXT | MY_UNPACK_FILENAME);
unlink(heartbeat_filename);
con->heartbeat_file= my_open(heartbeat_filename, O_CREAT|O_RDWR, MYF(0));
/*
No threads exist at this point in time, so this is thread safe.
*/
localtime_r(&result, &tm_tmp);
my_snprintf(buffer, sizeof(buffer),
"Starting up at %02d%02d%02d %2d:%02d:%02d\n",
tm_tmp.tm_year % 100,
tm_tmp.tm_mon+1,
tm_tmp.tm_mday,
tm_tmp.tm_hour,
tm_tmp.tm_min,
tm_tmp.tm_sec);
my_write(con->heartbeat_file, buffer, strlen(buffer), MYF(0));
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,
PTHREAD_CREATE_JOINABLE);
/* now create the thread */
if (pthread_create(&con->heartbeat_thread, &attr, mysql_heartbeat, (void *)con) != 0)
{
fprintf(stderr,"Could not create heartbeat thread!\n");
exit(0);
}
plugin->data= (void *)con;
DBUG_RETURN(0);
}
......@@ -58,10 +142,33 @@ static int daemon_example_plugin_init(void *p)
1 failure (cannot happen)
*/
static int daemon_example_plugin_deinit(void *p)
{
return(0);
DBUG_ENTER("daemon_example_plugin_deinit");
char buffer[HEART_STRING_BUFFER];
struct st_plugin_int *plugin= (struct st_plugin_int *)p;
struct mysql_heartbeat_context *con= (struct mysql_heartbeat_context *)plugin->data;
time_t result= time(NULL);
struct tm tm_tmp;
pthread_cancel(con->heartbeat_thread);
localtime_r(&result, &tm_tmp);
my_snprintf(buffer, sizeof(buffer),
"Shutting down at %02d%02d%02d %2d:%02d:%02d\n",
tm_tmp.tm_year % 100,
tm_tmp.tm_mon+1,
tm_tmp.tm_mday,
tm_tmp.tm_hour,
tm_tmp.tm_min,
tm_tmp.tm_sec);
my_write(con->heartbeat_file, buffer, strlen(buffer), MYF(0));
my_close(con->heartbeat_file, MYF(0));
my_free((char *)con, MYF(0));
DBUG_RETURN(0);
}
struct st_mysql_daemon daemon_example_plugin=
......@@ -77,7 +184,7 @@ mysql_declare_plugin(daemon_example)
&daemon_example_plugin,
"daemon_example",
"Brian Aker",
"Daemon example that tests init and deinit of a plugin",
"Daemon example, creates a heartbeat beat file in mysql-heartbeat.log",
PLUGIN_LICENSE_GPL,
daemon_example_plugin_init, /* Plugin Init */
daemon_example_plugin_deinit, /* Plugin Deinit */
......
......@@ -31,17 +31,26 @@ const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{ C_STRING_WITH_LEN("UDF") },
{ C_STRING_WITH_LEN("STORAGE ENGINE") },
{ C_STRING_WITH_LEN("FTPARSER") },
{ C_STRING_WITH_LEN("DAEMON") }
{ C_STRING_WITH_LEN("DAEMON") },
{ C_STRING_WITH_LEN("INFORMATION SCHEMA") }
};
extern int initialize_schema_table(st_plugin_int *plugin);
extern int finalize_schema_table(st_plugin_int *plugin);
/*
The number of elements in both plugin_type_initialize and
plugin_type_deinitialize should equal to the number of plugins
defined.
*/
plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
0,ha_initialize_handlerton,0,0
0,ha_initialize_handlerton,0,0,initialize_schema_table
};
plugin_type_init plugin_type_deinitialize[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
0,ha_finalize_handlerton,0,0
0,ha_finalize_handlerton,0,0,finalize_schema_table
};
static const char *plugin_interface_version_sym=
......@@ -58,14 +67,16 @@ static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
0x0000,
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION,
MYSQL_DAEMON_INTERFACE_VERSION
MYSQL_DAEMON_INTERFACE_VERSION,
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};
static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]=
{
0x0000, /* UDF: not implemented */
MYSQL_HANDLERTON_INTERFACE_VERSION,
MYSQL_FTPARSER_INTERFACE_VERSION,
MYSQL_DAEMON_INTERFACE_VERSION
MYSQL_DAEMON_INTERFACE_VERSION,
MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
};
static DYNAMIC_ARRAY plugin_dl_array;
......
......@@ -2451,10 +2451,48 @@ int make_db_list(THD *thd, List<char> *files,
mysql_data_home, NullS, 1) != FIND_FILES_OK);
}
struct st_add_schema_table
{
List<char> *files;
const char *wild;
};
static my_bool add_schema_table(THD *thd, st_plugin_int *plugin,
void* p_data)
{
st_add_schema_table *data= (st_add_schema_table *)p_data;
List<char> *file_list= data->files;
const char *wild= data->wild;
ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
DBUG_ENTER("add_schema_table");
if (schema_table->hidden)
DBUG_RETURN(0);
if (wild)
{
if (lower_case_table_names)
{
if (wild_case_compare(files_charset_info,
schema_table->table_name,
wild))
DBUG_RETURN(0);
}
else if (wild_compare(schema_table->table_name, wild, 0))
DBUG_RETURN(0);
}
if (file_list->push_back(thd->strdup(schema_table->table_name)))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
int schema_tables_add(THD *thd, List<char> *files, const char *wild)
{
ST_SCHEMA_TABLE *tmp_schema_table= schema_tables;
st_add_schema_table add_data;
DBUG_ENTER("schema_tables_add");
for (; tmp_schema_table->table_name; tmp_schema_table++)
{
if (tmp_schema_table->hidden)
......@@ -2472,9 +2510,16 @@ int schema_tables_add(THD *thd, List<char> *files, const char *wild)
continue;
}
if (files->push_back(thd->strdup(tmp_schema_table->table_name)))
return 1;
DBUG_RETURN(1);
}
return 0;
add_data.files= files;
add_data.wild= wild;
if (plugin_foreach(thd, add_schema_table,
MYSQL_INFORMATION_SCHEMA_PLUGIN, &add_data))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
......@@ -4511,6 +4556,44 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables,
DBUG_RETURN(0);
}
struct schema_table_ref
{
const char *table_name;
ST_SCHEMA_TABLE *schema_table;
};
/*
Find schema_tables elment by name
SYNOPSIS
find_schema_table_in_plugin()
thd thread handler
plugin plugin
table_name table name
RETURN
0 table not found
1 found the schema table
*/
static my_bool find_schema_table_in_plugin(THD *thd, st_plugin_int *plugin,
void* p_table)
{
schema_table_ref *p_schema_table= (schema_table_ref *)p_table;
const char* table_name= p_schema_table->table_name;
ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
DBUG_ENTER("find_schema_table_in_plugin");
if (!my_strcasecmp(system_charset_info,
schema_table->table_name,
table_name)) {
p_schema_table->schema_table= schema_table;
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
/*
Find schema_tables elment by name
......@@ -4527,15 +4610,24 @@ get_referential_constraints_record(THD *thd, struct st_table_list *tables,
ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name)
{
schema_table_ref schema_table_a;
ST_SCHEMA_TABLE *schema_table= schema_tables;
DBUG_ENTER("find_schema_table");
for (; schema_table->table_name; schema_table++)
{
if (!my_strcasecmp(system_charset_info,
schema_table->table_name,
table_name))
return schema_table;
DBUG_RETURN(schema_table);
}
return 0;
schema_table_a.table_name= table_name;
if (plugin_foreach(thd, find_schema_table_in_plugin,
MYSQL_INFORMATION_SCHEMA_PLUGIN, &schema_table_a))
DBUG_RETURN(schema_table_a.schema_table);
DBUG_RETURN(NULL);
}
......@@ -5752,3 +5844,54 @@ ST_SCHEMA_TABLE schema_tables[]=
template class List_iterator_fast<char>;
template class List<char>;
#endif
int initialize_schema_table(st_plugin_int *plugin)
{
ST_SCHEMA_TABLE *schema_table;
DBUG_ENTER("initialize_schema_table");
if (!(schema_table= (ST_SCHEMA_TABLE *)my_malloc(sizeof(ST_SCHEMA_TABLE),
MYF(MY_WME | MY_ZEROFILL))))
DBUG_RETURN(1);
/* Historical Requirement */
plugin->data= schema_table; // shortcut for the future
if (plugin->plugin->init)
{
schema_table->create_table= create_schema_table;
schema_table->old_format= make_old_format;
schema_table->idx_field1= -1,
schema_table->idx_field2= -1;
if (plugin->plugin->init(schema_table))
{
sql_print_error("Plugin '%s' init function returned error.",
plugin->name.str);
goto err;
}
schema_table->table_name= plugin->name.str;
}
DBUG_RETURN(0);
err:
my_free((gptr)schema_table, MYF(0));
DBUG_RETURN(1);
}
int finalize_schema_table(st_plugin_int *plugin)
{
ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)plugin->data;
DBUG_ENTER("finalize_schema_table");
if (schema_table && plugin->plugin->deinit)
{
DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
if (plugin->plugin->deinit(NULL))
{
DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
plugin->name.str));
}
my_free((gptr)schema_table, MYF(0));
}
DBUG_RETURN(0);
}
......@@ -3,6 +3,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <m_ctype.h>
#include <my_getopt.h>
#include <mysql_version.h>
......@@ -15,10 +16,12 @@ static void get_options(int *argc,char * * *argv);
static void print_version(void);
static void usage(void);
static const char *opt_tmpdir;
static const char *new_auto_increment_value;
static const char *new_auto_increment;
unsigned long long new_auto_increment_value;
static const char *load_default_groups[]= { "archive_reader", 0 };
static char **default_argv;
int opt_check, opt_force, opt_quiet, opt_backup= 0;
int opt_check, opt_force, opt_quiet, opt_backup= 0, opt_extract_frm;
int opt_autoincrement;
int main(int argc, char *argv[])
{
......@@ -40,6 +43,35 @@ int main(int argc, char *argv[])
return 0;
}
if (opt_autoincrement)
{
azio_stream writer_handle;
if (new_auto_increment_value)
{
if (reader_handle.auto_increment >= new_auto_increment_value)
{
printf("Value is lower then current value\n");
goto end;
}
}
else
{
new_auto_increment_value= reader_handle.auto_increment + 1;
}
if (!(ret= azopen(&writer_handle, argv[0], O_CREAT|O_RDWR|O_BINARY)))
{
printf("Could not open file for update: %s\n", argv[0]);
goto end;
}
writer_handle.auto_increment= new_auto_increment_value;
azclose(&writer_handle);
azflush(&reader_handle, Z_SYNC_FLUSH);
}
printf("Version %u\n", reader_handle.version);
if (reader_handle.version > 2)
{
......@@ -53,6 +85,20 @@ int main(int argc, char *argv[])
printf("\tLongest Row %u\n", reader_handle.longest_row);
printf("\tShortest Row %u\n", reader_handle.shortest_row);
printf("\tState %s\n", ( reader_handle.dirty ? "dirty" : "clean"));
printf("\tFRM stored at %u\n", reader_handle.frm_start_pos);
printf("\tComment stored at %u\n", reader_handle.comment_start_pos);
printf("\tData starts at %u\n", (unsigned int)reader_handle.start);
if (reader_handle.frm_start_pos)
printf("\tFRM length %u\n", reader_handle.frm_length);
if (reader_handle.comment_start_pos)
{
char *comment =
(char *) malloc(sizeof(char) * reader_handle.comment_length);
azread_comment(&reader_handle, comment);
printf("\tComment length %u\n\t\t%.*s\n", reader_handle.comment_length,
reader_handle.comment_length, comment);
free(comment);
}
}
else
{
......@@ -148,6 +194,23 @@ int main(int argc, char *argv[])
}
writer_handle.auto_increment= reader_handle.auto_increment;
if (reader_handle.frm_length)
{
char *ptr;
ptr= (char *)my_malloc(sizeof(char) * reader_handle.frm_length, MYF(0));
azread_frm(&reader_handle, ptr);
azwrite_frm(&writer_handle, ptr, reader_handle.frm_length);
my_free(ptr, MYF(0));
}
if (reader_handle.comment_length)
{
char *ptr;
ptr= (char *)my_malloc(sizeof(char) * reader_handle.comment_length, MYF(0));
azread_comment(&reader_handle, ptr);
azwrite_comment(&writer_handle, ptr, reader_handle.comment_length);
my_free(ptr, MYF(0));
}
while ((read= azread(&reader_handle, (byte *)size_buffer,
ARCHIVE_ROW_HEADER_SIZE, &error)))
......@@ -192,6 +255,18 @@ int main(int argc, char *argv[])
azclose(&writer_handle);
}
if (opt_extract_frm)
{
File frm_file;
char *ptr;
frm_file= my_open(argv[1], O_CREAT|O_RDWR|O_BINARY, MYF(0));
ptr= (char *)my_malloc(sizeof(char) * reader_handle.frm_length, MYF(0));
azread_frm(&reader_handle, ptr);
my_write(frm_file, ptr, reader_handle.frm_length, MYF(0));
my_close(frm_file, MYF(0));
my_free(ptr, MYF(0));
}
end:
printf("\n");
azclose(&reader_handle);
......@@ -211,6 +286,9 @@ get_one_option(int optid,
case 'c':
opt_check= 1;
break;
case 'e':
opt_extract_frm= 1;
break;
case 'f':
opt_force= 1;
printf("Not implemented yet\n");
......@@ -226,7 +304,11 @@ get_one_option(int optid,
printf("Not implemented yet\n");
break;
case 'A':
printf("Not implemented yet\n");
opt_autoincrement= 1;
if (argument)
new_auto_increment_value= strtoull(argument, NULL, 0);
else
new_auto_increment_value= 0;
break;
case '?':
usage();
......@@ -257,6 +339,9 @@ static struct my_option my_long_options[] =
"Output debug log. Often this is 'd:t:o,filename'.",
0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"extract-frm", 'e',
"Extract the frm file.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"force", 'f',
"Restart with -r if there are any errors in the table.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
......@@ -268,9 +353,9 @@ static struct my_option my_long_options[] =
{"repair", 'r', "Repair a damaged Archive version 3 or above file.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"set-auto-increment", 'A',
"Force auto_increment to start at this or higher value.",
(gptr*) &new_auto_increment_value,
(gptr*) &new_auto_increment_value,
"Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1.",
(gptr*) &new_auto_increment,
(gptr*) &new_auto_increment,
0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"silent", 's',
"Only print errors. One can use two -s to make archive_reader very silent.",
......
......@@ -17,11 +17,14 @@
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <my_getopt.h>
#include <mysql_version.h>
#define ARCHIVE_ROW_HEADER_SIZE 4
#define COMMENT_STRING "Your bases"
#define FRM_STRING "My bases"
#define TEST_FILENAME "test.az"
#define TEST_STRING_INIT "YOU don't know about me without you have read a book by the name of The Adventures of Tom Sawyer; but that ain't no matter. That book was made by Mr. Mark Twain, and he told the truth, mainly. There was things which he stretched, but mainly he told the truth. That is nothing. I never seen anybody but lied one time or another, without it was Aunt Polly, or the widow, or maybe Mary. Aunt Polly--Tom's Aunt Polly, she is--and Mary, and the Widow Douglas is all told about in that book, which is mostly a true book, with some stretchers, as I said before. Now the way that the book winds up is this: Tom and me found the money that the robbers hid in the cave, and it made us rich. We got six thousand dollars apiece--all gold. It was an awful sight of money when it was piled up. Well, Judge Thatcher he took it and put it out at interest, and it fetched us a dollar a day apiece all the year round --more than a body could tell what to do with. The Widow Douglas she took me for her son, and allowed she would..."
#define TEST_LOOP_NUM 100
......@@ -44,6 +47,7 @@ int size_test(unsigned long long length, unsigned long long rows_to_test_for);
int main(int argc, char *argv[])
{
unsigned int ret;
char comment_str[10];
int error;
unsigned int x;
......@@ -67,6 +71,19 @@ int main(int argc, char *argv[])
return 0;
}
azwrite_comment(&writer_handle, (char *)COMMENT_STRING,
(unsigned int)strlen(COMMENT_STRING));
azread_comment(&writer_handle, comment_str);
assert(!memcmp(COMMENT_STRING, comment_str,
strlen(COMMENT_STRING)));
azwrite_frm(&writer_handle, (char *)FRM_STRING,
(unsigned int)strlen(FRM_STRING));
azread_frm(&writer_handle, comment_str);
assert(!memcmp(FRM_STRING, comment_str,
strlen(FRM_STRING)));
if (!(ret= azopen(&reader_handle, TEST_FILENAME, O_RDONLY|O_BINARY)))
{
printf("Could not open test file\n");
......@@ -87,6 +104,10 @@ int main(int argc, char *argv[])
}
azflush(&writer_handle, Z_SYNC_FLUSH);
azread_comment(&writer_handle, comment_str);
assert(!memcmp(COMMENT_STRING, comment_str,
strlen(COMMENT_STRING)));
/* Lets test that our internal stats are good */
assert(writer_handle.rows == TEST_LOOP_NUM);
......@@ -94,15 +115,16 @@ int main(int argc, char *argv[])
azflush(&reader_handle, Z_SYNC_FLUSH);
assert(reader_handle.rows == TEST_LOOP_NUM);
assert(reader_handle.auto_increment == 0);
assert(reader_handle.check_point == 62);
assert(reader_handle.check_point == 96);
assert(reader_handle.forced_flushes == 1);
assert(reader_handle.comment_length == 10);
assert(reader_handle.dirty == AZ_STATE_SAVED);
writer_handle.auto_increment= 4;
azflush(&writer_handle, Z_SYNC_FLUSH);
assert(writer_handle.rows == TEST_LOOP_NUM);
assert(writer_handle.auto_increment == 4);
assert(writer_handle.check_point == 62);
assert(writer_handle.check_point == 96);
assert(writer_handle.forced_flushes == 2);
assert(writer_handle.dirty == AZ_STATE_SAVED);
......@@ -181,7 +203,7 @@ int main(int argc, char *argv[])
azflush(&reader_handle, Z_SYNC_FLUSH);
assert(reader_handle.rows == 102);
assert(reader_handle.auto_increment == 4);
assert(reader_handle.check_point == 1256);
assert(reader_handle.check_point == 1290);
assert(reader_handle.forced_flushes == 4);
assert(reader_handle.dirty == AZ_STATE_SAVED);
......
......@@ -128,7 +128,12 @@ int az_open (azio_stream *s, const char *path, int Flags, File fd)
s->longest_row= 0;
s->auto_increment= 0;
s->check_point= 0;
s->comment_start_pos= 0;
s->comment_length= 0;
s->frm_start_pos= 0;
s->frm_length= 0;
s->dirty= 1; /* We create the file dirty */
s->start = AZHEADER_SIZE + AZMETA_BUFFER_SIZE;
write_header(s);
my_seek(s->file, 0, MY_SEEK_END, MYF(0));
}
......@@ -153,7 +158,6 @@ void write_header(azio_stream *s)
char buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
char *ptr= buffer;
s->start = AZHEADER_SIZE + AZMETA_BUFFER_SIZE;
s->block_size= AZ_BUFSIZE;
s->version = (unsigned char)az_magic[1];
s->minor_version = (unsigned char)az_magic[2];
......@@ -167,8 +171,12 @@ void write_header(azio_stream *s)
*(ptr + AZ_BLOCK_POS)= (unsigned char)(s->block_size/1024); /* Reserved for block size */
*(ptr + AZ_STRATEGY_POS)= (unsigned char)Z_DEFAULT_STRATEGY; /* Compression Type */
int4store(ptr + AZ_FRM_POS, 0); /* FRM Block */
int4store(ptr + AZ_FRM_POS, s->frm_start_pos); /* FRM Block */
int4store(ptr + AZ_FRM_LENGTH_POS, s->frm_length); /* FRM Block */
int4store(ptr + AZ_COMMENT_POS, s->comment_start_pos); /* COMMENT Block */
int4store(ptr + AZ_COMMENT_LENGTH_POS, s->comment_length); /* COMMENT Block */
int4store(ptr + AZ_META_POS, 0); /* Meta Block */
int4store(ptr + AZ_META_LENGTH_POS, 0); /* Meta Block */
int8store(ptr + AZ_START_POS, (unsigned long long)s->start); /* Start of Data Block Index Block */
int8store(ptr + AZ_ROW_POS, (unsigned long long)s->rows); /* Start of Data Block Index Block */
int8store(ptr + AZ_FLUSH_POS, (unsigned long long)s->forced_flushes); /* Start of Data Block Index Block */
......@@ -176,10 +184,12 @@ void write_header(azio_stream *s)
int8store(ptr + AZ_AUTOINCREMENT_POS, (unsigned long long)s->auto_increment); /* Start of Data Block Index Block */
int4store(ptr+ AZ_LONGEST_POS , s->longest_row); /* Longest row */
int4store(ptr+ AZ_SHORTEST_POS, s->shortest_row); /* Shorest row */
int4store(ptr+ AZ_FRM_POS,
AZHEADER_SIZE + AZMETA_BUFFER_SIZE); /* FRM position */
*(ptr + AZ_DIRTY_POS)= (unsigned char)s->dirty; /* Start of Data Block Index Block */
/* Always begin at the begining, and end there as well */
my_pwrite(s->file, buffer, (uint)s->start, 0, MYF(0));
my_pwrite(s->file, buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0, MYF(0));
}
/* ===========================================================================
......@@ -303,6 +313,8 @@ void check_header(azio_stream *s)
buffer[len]= get_byte(s);
s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
read_header(s, buffer);
for (; len < s->start; len++)
get_byte(s);
}
else
{
......@@ -326,6 +338,10 @@ void read_header(azio_stream *s, unsigned char *buffer)
s->auto_increment= (unsigned long long)uint8korr(buffer + AZ_AUTOINCREMENT_POS);
s->longest_row= (unsigned int)uint4korr(buffer + AZ_LONGEST_POS);
s->shortest_row= (unsigned int)uint4korr(buffer + AZ_SHORTEST_POS);
s->frm_start_pos= (unsigned int)uint4korr(buffer + AZ_FRM_POS);
s->frm_length= (unsigned int)uint4korr(buffer + AZ_FRM_LENGTH_POS);
s->comment_start_pos= (unsigned int)uint4korr(buffer + AZ_COMMENT_POS);
s->comment_length= (unsigned int)uint4korr(buffer + AZ_COMMENT_LENGTH_POS);
s->dirty= (unsigned int)buffer[AZ_DIRTY_POS];
}
else
......@@ -497,7 +513,6 @@ unsigned int azwrite (azio_stream *s, voidpc buf, unsigned int len)
s->stream.next_in = (Bytef*)buf;
s->stream.avail_in = len;
s->rows++;
while (s->stream.avail_in != 0)
......@@ -782,3 +797,65 @@ int azclose (azio_stream *s)
return destroy(s);
}
/*
Though this was added to support MySQL's FRM file, anything can be
stored in this location.
*/
int azwrite_frm(azio_stream *s, char *blob, unsigned int length)
{
if (s->mode == 'r')
return 1;
if (s->rows > 0)
return 1;
s->frm_start_pos= s->start;
s->frm_length= length;
s->start+= length;
my_pwrite(s->file, blob, s->frm_length, s->frm_start_pos, MYF(0));
write_header(s);
my_seek(s->file, 0, MY_SEEK_END, MYF(0));
return 0;
}
int azread_frm(azio_stream *s, char *blob)
{
my_pread(s->file, blob, s->frm_length, s->frm_start_pos, MYF(0));
return 0;
}
/*
Simple comment field
*/
int azwrite_comment(azio_stream *s, char *blob, unsigned int length)
{
if (s->mode == 'r')
return 1;
if (s->rows > 0)
return 1;
s->comment_start_pos= s->start;
s->comment_length= length;
s->start+= length;
my_pwrite(s->file, blob, s->comment_length, s->comment_start_pos, MYF(0));
write_header(s);
my_seek(s->file, 0, MY_SEEK_END, MYF(0));
return 0;
}
int azread_comment(azio_stream *s, char *blob)
{
my_pread(s->file, blob, s->comment_length, s->comment_start_pos, MYF(0));
return 0;
}
......@@ -49,9 +49,10 @@ extern "C" {
#define AZMETA_BUFFER_SIZE sizeof(unsigned long long) \
+ sizeof(unsigned long long) + sizeof(unsigned long long) + sizeof(unsigned long long) \
+ sizeof(unsigned int) + sizeof(unsigned int) \
+ sizeof(unsigned int) + sizeof(unsigned int) \
+ sizeof(unsigned char)
#define AZHEADER_SIZE 21
#define AZHEADER_SIZE 29
#define AZ_MAGIC_POS 0
#define AZ_VERSION_POS 1
......@@ -59,15 +60,19 @@ extern "C" {
#define AZ_BLOCK_POS 3
#define AZ_STRATEGY_POS 4
#define AZ_FRM_POS 5
#define AZ_META_POS 9
#define AZ_START_POS 13
#define AZ_ROW_POS 21
#define AZ_FLUSH_POS 29
#define AZ_CHECK_POS 37
#define AZ_AUTOINCREMENT_POS 45
#define AZ_LONGEST_POS 53
#define AZ_SHORTEST_POS 57
#define AZ_DIRTY_POS 61
#define AZ_FRM_LENGTH_POS 9
#define AZ_META_POS 13
#define AZ_META_LENGTH_POS 17
#define AZ_START_POS 21
#define AZ_ROW_POS 29
#define AZ_FLUSH_POS 37
#define AZ_CHECK_POS 45
#define AZ_AUTOINCREMENT_POS 53
#define AZ_LONGEST_POS 61
#define AZ_SHORTEST_POS 65
#define AZ_COMMENT_POS 69
#define AZ_COMMENT_LENGTH_POS 73
#define AZ_DIRTY_POS 77
/*
......@@ -220,6 +225,10 @@ typedef struct azio_stream {
unsigned int longest_row; /* Longest row */
unsigned int shortest_row; /* Shortest row */
unsigned char dirty; /* State of file */
unsigned int frm_start_pos; /* Position for start of FRM */
unsigned int frm_length; /* Position for start of FRM */
unsigned int comment_start_pos; /* Position for start of comment */
unsigned int comment_length; /* Position for start of comment */
} azio_stream;
/* basic functions */
......@@ -322,6 +331,11 @@ extern int azclose(azio_stream *file);
error number (see function gzerror below).
*/
extern int azwrite_frm (azio_stream *s, char *blob, unsigned int length);
extern int azread_frm (azio_stream *s, char *blob);
extern int azwrite_comment (azio_stream *s, char *blob, unsigned int length);
extern int azread_comment (azio_stream *s, char *blob);
#ifdef __cplusplus
}
#endif
......@@ -28,13 +28,13 @@
/*
First, if you want to understand storage engines you should look at
ha_example.cc and ha_example.h.
This example was written as a test case for a customer who needed
a storage engine without indexes that could compress data very well.
So, welcome to a completely compressed storage engine. This storage
engine only does inserts. No replace, deletes, or updates. All reads are
complete table scans. Compression is done through azip (bzip compresses
better, but only marginally, if someone asks I could add support for
it too, but beaware that it costs a lot more in CPU time then azip).
complete table scans. Compression is done through a combination of packing
and making use of the zlib library
We keep a file pointer open for each instance of ha_archive for each read
but for writes we keep one open file handle just for that. We flush it
......@@ -80,38 +80,17 @@
TODO:
Add bzip optional support.
Allow users to set compression level.
Implement versioning, should be easy.
Allow for errors, find a way to mark bad rows.
Add optional feature so that rows can be flushed at interval (which will cause less
compression but may speed up ordered searches).
Checkpoint the meta file to allow for faster rebuilds.
Dirty open (right now the meta file is repaired if a crash occured).
Option to allow for dirty reads, this would lower the sync calls, which would make
inserts a lot faster, but would mean highly arbitrary reads.
-Brian
*/
/*
Notes on file formats.
The Meta file is layed out as:
check - Just an int of 254 to make sure that the the file we are opening was
never corrupted.
version - The current version of the file format.
rows - This is an unsigned long long which is the number of rows in the data
file.
check point - Reserved for future use
auto increment - MAX value for autoincrement
dirty - Status of the file, whether or not its values are the latest. This
flag is what causes a repair to occur
The data file:
check - Just an int of 254 to make sure that the the file we are opening was
never corrupted.
version - The current version of the file format.
data - The data is stored in a "row +blobs" format.
*/
/* Variables for archive share methods */
pthread_mutex_t archive_mutex;
......@@ -121,13 +100,6 @@ static HASH archive_open_tables;
#define ARZ ".ARZ" // The data file
#define ARN ".ARN" // Files used during an optimize call
#define ARM ".ARM" // Meta file (deprecated)
/*
uchar + uchar + ulonglong + ulonglong + ulonglong + ulonglong + FN_REFLEN
+ uchar
*/
#define META_BUFFER_SIZE sizeof(uchar) + sizeof(uchar) + sizeof(ulonglong) \
+ sizeof(ulonglong) + sizeof(ulonglong) + sizeof(ulonglong) + FN_REFLEN \
+ sizeof(uchar)
/*
uchar + uchar
......@@ -139,6 +111,10 @@ static HASH archive_open_tables;
static handler *archive_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root);
int archive_discover(handlerton *hton, THD* thd, const char *db,
const char *name,
const void** frmblob,
uint* frmlen);
/*
Number of rows that will force a bulk insert.
......@@ -186,10 +162,11 @@ int archive_db_init(void *p)
handlerton *archive_hton;
archive_hton= (handlerton *)p;
archive_hton->state=SHOW_OPTION_YES;
archive_hton->db_type=DB_TYPE_ARCHIVE_DB;
archive_hton->create=archive_create_handler;
archive_hton->flags=HTON_NO_FLAGS;
archive_hton->state= SHOW_OPTION_YES;
archive_hton->db_type= DB_TYPE_ARCHIVE_DB;
archive_hton->create= archive_create_handler;
archive_hton->flags= HTON_NO_FLAGS;
archive_hton->discover= archive_discover;
if (pthread_mutex_init(&archive_mutex, MY_MUTEX_INIT_FAST))
goto error;
......@@ -236,6 +213,46 @@ ha_archive::ha_archive(handlerton *hton, TABLE_SHARE *table_arg)
ref_length = sizeof(my_off_t);
}
int archive_discover(handlerton *hton, THD* thd, const char *db,
const char *name,
const void** frmblob,
uint* frmlen)
{
DBUG_ENTER("archive_discover");
DBUG_PRINT("archive_discover", ("db: %s, name: %s", db, name));
azio_stream frm_stream;
char az_file[FN_REFLEN];
char *frm_ptr;
MY_STAT file_stat;
fn_format(az_file, name, db, ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
if (!(my_stat(az_file, &file_stat, MYF(0))))
goto err;
if (!(azopen(&frm_stream, az_file, O_RDONLY|O_BINARY)))
{
if (errno == EROFS || errno == EACCES)
DBUG_RETURN(my_errno= errno);
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
}
if (frm_stream.frm_length == 0)
goto err;
frm_ptr= (char *)my_malloc(sizeof(char) * frm_stream.frm_length, MYF(0));
azread_frm(&frm_stream, frm_ptr);
azclose(&frm_stream);
*frmlen= frm_stream.frm_length;
*frmblob= frm_ptr;
DBUG_RETURN(0);
err:
my_errno= 0;
DBUG_RETURN(1);
}
/*
This method reads the header of a datafile and returns whether or not it was successful.
*/
......@@ -321,7 +338,7 @@ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name,
share->crashed= FALSE;
share->archive_write_open= FALSE;
fn_format(share->data_file_name, table_name, "",
ARZ,MY_REPLACE_EXT|MY_UNPACK_FILENAME);
ARZ, MY_REPLACE_EXT | MY_UNPACK_FILENAME);
strmov(share->table_name, table_name);
DBUG_PRINT("ha_archive", ("Data File %s",
share->data_file_name));
......@@ -540,6 +557,9 @@ int ha_archive::create(const char *name, TABLE *table_arg,
char linkname[FN_REFLEN];
int error;
azio_stream create_stream; /* Archive file we are working with */
File frm_file; /* File handler for readers */
MY_STAT file_stat; // Stat information for the data file
byte *frm_ptr;
DBUG_ENTER("ha_archive::create");
......@@ -578,7 +598,6 @@ int ha_archive::create(const char *name, TABLE *table_arg,
MY_REPLACE_EXT | MY_UNPACK_FILENAME);
fn_format(linkname, name, "", ARZ,
MY_REPLACE_EXT | MY_UNPACK_FILENAME);
//MY_UNPACK_FILENAME | MY_APPEND_EXT);
}
else
{
......@@ -587,28 +606,56 @@ int ha_archive::create(const char *name, TABLE *table_arg,
linkname[0]= 0;
}
if (!(azopen(&create_stream, name_buff, O_CREAT|O_RDWR|O_BINARY)))
/*
There is a chance that the file was "discovered". In this case
just use whatever file is there.
*/
if (!(my_stat(name_buff, &file_stat, MYF(0))))
{
error= errno;
goto error2;
}
my_errno= 0;
if (!(azopen(&create_stream, name_buff, O_CREAT|O_RDWR|O_BINARY)))
{
error= errno;
goto error2;
}
if (linkname[0])
my_symlink(name_buff, linkname, MYF(0));
if (linkname[0])
my_symlink(name_buff, linkname, MYF(0));
fn_format(name_buff, name, "", ".frm",
MY_REPLACE_EXT | MY_UNPACK_FILENAME);
/*
Here is where we open up the frm and pass it to archive to store
*/
frm_file= my_open(name_buff, O_RDONLY, MYF(0));
VOID(my_fstat(frm_file, &file_stat, MYF(MY_WME)));
frm_ptr= (byte *)my_malloc(sizeof(byte) * file_stat.st_size , MYF(0));
my_read(frm_file, frm_ptr, file_stat.st_size, MYF(0));
azwrite_frm(&create_stream, (char *)frm_ptr, file_stat.st_size);
my_close(frm_file, MYF(0));
my_free((gptr)frm_ptr, MYF(0));
if (create_info->comment.str)
azwrite_comment(&create_stream, create_info->comment.str,
create_info->comment.length);
/*
Yes you need to do this, because the starting value
for the autoincrement may not be zero.
*/
create_stream.auto_increment= stats.auto_increment_value;
if (azclose(&create_stream))
{
error= errno;
goto error2;
}
}
else
my_errno= 0;
DBUG_PRINT("ha_archive", ("Creating File %s", name_buff));
DBUG_PRINT("ha_archive", ("Creating Link %s", linkname));
/*
Yes you need to do this, because the starting value
for the autoincrement may not be zero.
*/
create_stream.auto_increment= stats.auto_increment_value;
if (azclose(&create_stream))
{
error= errno;
goto error2;
}
DBUG_RETURN(0);
......@@ -686,8 +733,9 @@ unsigned int ha_archive::pack_row(byte *record)
for (Field **field=table->field ; *field ; field++)
{
ptr=(byte*) (*field)->pack((char*) ptr,
(char*) record + (*field)->offset(record));
if (!((*field)->is_null()))
ptr=(byte*) (*field)->pack((char*) ptr,
(char*) record + (*field)->offset(record));
}
int4store(record_buffer->buffer, (int)(ptr - record_buffer->buffer -
......@@ -736,23 +784,22 @@ int ha_archive::write_row(byte *buf)
temp_auto= table->next_number_field->val_int();
/*
Simple optimization to see if we fail for duplicate key immediatly
because we have just given out this value.
We don't support decremening auto_increment. They make the performance
just cry.
*/
if (temp_auto == share->archive_write.auto_increment &&
if (temp_auto <= share->archive_write.auto_increment &&
mkey->flags & HA_NOSAME)
{
rc= HA_ERR_FOUND_DUPP_KEY;
goto error;
}
#ifdef DEAD_CODE
/*
Bad news, this will cause a search for the unique value which is very
expensive since we will have to do a table scan which will lock up
all other writers during this period. This could perhaps be optimized
in the future.
*/
if (temp_auto < share->archive_write.auto_increment &&
mkey->flags & HA_NOSAME)
{
/*
First we create a buffer that we can use for reading rows, and can pass
......@@ -790,6 +837,7 @@ int ha_archive::write_row(byte *buf)
}
}
}
#endif
else
{
if (temp_auto > share->archive_write.auto_increment)
......@@ -1039,7 +1087,11 @@ int ha_archive::unpack_row(azio_stream *file_to_read, byte *record)
memcpy(record, ptr, table->s->null_bytes);
ptr+= table->s->null_bytes;
for (Field **field=table->field ; *field ; field++)
ptr= (*field)->unpack((char *)record + (*field)->offset(table->record[0]), ptr);
if (!((*field)->is_null()))
{
ptr= (*field)->unpack((char *)record +
(*field)->offset(table->record[0]), ptr);
}
DBUG_RETURN(0);
}
......@@ -1232,7 +1284,7 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt)
/* Lets create a file to contain the new data */
fn_format(writer_filename, share->table_name, "", ARN,
MY_REPLACE_EXT|MY_UNPACK_FILENAME);
MY_REPLACE_EXT | MY_UNPACK_FILENAME);
if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR|O_BINARY)))
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
......@@ -1364,7 +1416,7 @@ void ha_archive::update_create_info(HA_CREATE_INFO *create_info)
DBUG_ENTER("ha_archive::update_create_info");
ha_archive::info(HA_STATUS_AUTO);
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
if (create_info->used_fields & HA_CREATE_USED_AUTO)
{
/*
Internally Archive keeps track of last used, not next used.
......
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