summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/client_priv.h1
-rw-r--r--client/mysqlslap.c331
-rw-r--r--mysql-test/t/mysqlslap.test2
-rw-r--r--sql/authors.h1
4 files changed, 269 insertions, 66 deletions
diff --git a/client/client_priv.h b/client/client_priv.h
index 00ef1a79d96..b6543870528 100644
--- a/client/client_priv.h
+++ b/client/client_priv.h
@@ -61,6 +61,7 @@ enum options_client
OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES,
+ OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES,
OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM,
OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM,
OPT_MYSQL_REPLACE_INTO, OPT_BASE64_OUTPUT, OPT_SERVER_ID,
diff --git a/client/mysqlslap.c b/client/mysqlslap.c
index 1dc49aa06f3..0010d8e46ae 100644
--- a/client/mysqlslap.c
+++ b/client/mysqlslap.c
@@ -145,13 +145,22 @@ const char *auto_generate_sql_type= "mixed";
static unsigned long connect_flags= CLIENT_MULTI_RESULTS;
-static int verbose, num_int_cols, num_char_cols, delimiter_length;
+static int verbose, delimiter_length;
+const char *num_int_cols_opt;
+const char *num_char_cols_opt;
+/* Yes, we do set defaults here */
+static unsigned int num_int_cols= 1;
+static unsigned int num_char_cols= 1;
+static unsigned int num_int_cols_index= 0;
+static unsigned int num_char_cols_index= 0;
+
static unsigned int iterations;
static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
static ulonglong actual_queries= 0;
static ulonglong auto_actual_queries;
static ulonglong auto_generate_sql_unique_write_number;
static ulonglong auto_generate_sql_unique_query_number;
+static unsigned int auto_generate_sql_secondary_indexes;
static ulonglong num_of_query;
static ulonglong auto_generate_sql_number;
const char *concurrency_str= NULL;
@@ -176,9 +185,21 @@ struct statement {
char *string;
size_t length;
unsigned char type;
+ char *option;
+ size_t option_length;
statement *next;
};
+typedef struct option_string option_string;
+
+struct option_string {
+ char *string;
+ size_t length;
+ char *option;
+ size_t option_length;
+ option_string *next;
+};
+
typedef struct stats stats;
struct stats {
@@ -209,30 +230,32 @@ struct conclusions {
unsigned long long min_rows;
};
+static option_string *engine_options= NULL;
static statement *create_statements= NULL,
- *engine_statements= NULL,
*query_statements= NULL;
/* Prototypes */
void print_conclusions(conclusions *con);
void print_conclusions_csv(conclusions *con);
-void generate_stats(conclusions *con, statement *eng, stats *sptr);
+void generate_stats(conclusions *con, option_string *eng, stats *sptr);
uint parse_comma(const char *string, uint **range);
uint parse_delimiter(const char *script, statement **stmt, char delm);
+uint parse_option(const char *origin, option_string **stmt, char delm);
static int drop_schema(MYSQL *mysql, const char *db);
uint get_random_string(char *buf);
static statement *build_table_string(void);
static statement *build_insert_string(void);
static statement *build_update_string(void);
static statement * build_select_string(my_bool key);
-static int generate_primary_key_list(MYSQL *mysql, statement *engine_stmt);
+static int generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt);
static int drop_primary_key_list(void);
static int create_schema(MYSQL *mysql, const char *db, statement *stmt,
- statement *engine_stmt);
+ option_string *engine_stmt);
static int run_scheduler(stats *sptr, statement *stmts, uint concur,
ulonglong limit);
int run_task(thread_context *con);
void statement_cleanup(statement *stmt);
+void option_cleanup(option_string *stmt);
static const char ALPHANUMERICS[]=
"0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
@@ -268,7 +291,7 @@ int main(int argc, char **argv)
MYSQL mysql;
unsigned int x;
unsigned long long client_limit;
- statement *eptr;
+ option_string *eptr;
#ifdef __WIN__
opt_use_threads= 1;
@@ -330,7 +353,7 @@ int main(int argc, char **argv)
}
/* Main iterations loop */
- eptr= engine_statements;
+ eptr= engine_options;
do
{
/* For the final stage we run whatever queries we were asked to run */
@@ -419,8 +442,8 @@ int main(int argc, char **argv)
my_free((gptr)concurrency, MYF(0));
statement_cleanup(create_statements);
- statement_cleanup(engine_statements);
statement_cleanup(query_statements);
+ option_cleanup(engine_options);
#ifdef HAVE_SMEM
if (shared_memory_base_name)
@@ -456,9 +479,15 @@ static struct my_option my_long_options[] =
(gptr*) &auto_generate_sql_guid_primary,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
- "Load types are mixed, update, write, or read. Default is mixed\n",
+ "Load types are mixed, update, write, key, or read. Default is mixed\n",
(gptr*) &auto_generate_sql_type, (gptr*) &auto_generate_sql_type,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"auto-generate-sql-secondary-indexes",
+ OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES,
+ "Number of secondary indexes to add auto-generated tables.",
+ (gptr*) &auto_generate_sql_secondary_indexes,
+ (gptr*) &auto_generate_sql_secondary_indexes, 0,
+ GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"auto-generate-sql-unique-query-number",
OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM,
"Number of unique queries auto tests",
@@ -510,12 +539,12 @@ static struct my_option my_long_options[] =
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"number-char-cols", 'x',
"Number of VARCHAR columns to create table with if specifying --auto-generate-sql ",
- (gptr*) &num_char_cols, (gptr*) &num_char_cols, 0, GET_UINT, REQUIRED_ARG,
- 1, 0, 0, 0, 0, 0},
+ (gptr*) &num_char_cols_opt, (gptr*) &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG,
+ 0, 0, 0, 0, 0, 0},
{"number-int-cols", 'y',
"Number of INT columns to create table with if specifying --auto-generate-sql.",
- (gptr*) &num_int_cols, (gptr*) &num_int_cols, 0, GET_UINT, REQUIRED_ARG,
- 1, 0, 0, 0, 0, 0},
+ (gptr*) &num_int_cols_opt, (gptr*) &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG,
+ 0, 0, 0, 0, 0, 0},
{"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY,
"Limit each client to this number of queries (this is not exact).",
(gptr*) &num_of_query, (gptr*) &num_of_query, 0,
@@ -685,12 +714,12 @@ static statement *
build_table_string(void)
{
char buf[HUGE_STRING_LENGTH];
- int col_count;
+ unsigned int col_count;
statement *ptr;
DYNAMIC_STRING table_string;
DBUG_ENTER("build_table_string");
- DBUG_PRINT("info", ("num int cols %d num char cols %d",
+ DBUG_PRINT("info", ("num int cols %u num char cols %u",
num_int_cols, num_char_cols));
init_dynamic_string(&table_string, "", 1024, 1024);
@@ -699,12 +728,7 @@ build_table_string(void)
if (auto_generate_sql_autoincrement)
{
- if (snprintf(buf, HUGE_STRING_LENGTH, "id serial") > HUGE_STRING_LENGTH)
- {
- fprintf(stderr, "Memory Allocation error in create table\n");
- exit(1);
- }
- dynstr_append(&table_string, buf);
+ dynstr_append(&table_string, "id serial");
if (num_int_cols || num_char_cols)
dynstr_append(&table_string, ",");
@@ -712,12 +736,29 @@ build_table_string(void)
if (auto_generate_sql_guid_primary)
{
- if (snprintf(buf, HUGE_STRING_LENGTH, "id varchar(32) primary key") > HUGE_STRING_LENGTH)
+ dynstr_append(&table_string, "id varchar(32) primary key");
+
+ if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
+ dynstr_append(&table_string, ",");
+ }
+
+ if (auto_generate_sql_secondary_indexes)
+ {
+ unsigned int count;
+
+ for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
{
+ if (count) /* Except for the first pass we add a comma */
+ dynstr_append(&table_string, ",");
+
+ if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(32) unique key", count)
+ > HUGE_STRING_LENGTH)
+ {
fprintf(stderr, "Memory Allocation error in create table\n");
exit(1);
+ }
+ dynstr_append(&table_string, buf);
}
- dynstr_append(&table_string, buf);
if (num_int_cols || num_char_cols)
dynstr_append(&table_string, ",");
@@ -726,11 +767,23 @@ build_table_string(void)
if (num_int_cols)
for (col_count= 1; col_count <= num_int_cols; col_count++)
{
- if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32)", col_count)
- > HUGE_STRING_LENGTH)
+ if (num_int_cols_index)
{
- fprintf(stderr, "Memory Allocation error in create table\n");
- exit(1);
+ if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32), INDEX(intcol%d)",
+ col_count, col_count) > HUGE_STRING_LENGTH)
+ {
+ fprintf(stderr, "Memory Allocation error in create table\n");
+ exit(1);
+ }
+ }
+ else
+ {
+ if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32) ", col_count)
+ > HUGE_STRING_LENGTH)
+ {
+ fprintf(stderr, "Memory Allocation error in create table\n");
+ exit(1);
+ }
}
dynstr_append(&table_string, buf);
@@ -741,11 +794,24 @@ build_table_string(void)
if (num_char_cols)
for (col_count= 1; col_count <= num_char_cols; col_count++)
{
- if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)", col_count)
- > HUGE_STRING_LENGTH)
+ if (num_char_cols_index)
{
- fprintf(stderr, "Memory Allocation error in creating table\n");
- exit(1);
+ if (snprintf(buf, HUGE_STRING_LENGTH,
+ "charcol%d VARCHAR(128), INDEX(charcol%d) ",
+ col_count, col_count) > HUGE_STRING_LENGTH)
+ {
+ fprintf(stderr, "Memory Allocation error in creating table\n");
+ exit(1);
+ }
+ }
+ else
+ {
+ if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)",
+ col_count) > HUGE_STRING_LENGTH)
+ {
+ fprintf(stderr, "Memory Allocation error in creating table\n");
+ exit(1);
+ }
}
dynstr_append(&table_string, buf);
@@ -759,6 +825,7 @@ build_table_string(void)
ptr->string = (char *)my_malloc(table_string.length+1,
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
ptr->length= table_string.length+1;
+ ptr->type= CREATE_TABLE_TYPE;
strmov(ptr->string, table_string.str);
dynstr_free(&table_string);
DBUG_RETURN(ptr);
@@ -774,7 +841,7 @@ static statement *
build_update_string(void)
{
char buf[HUGE_STRING_LENGTH];
- int col_count;
+ unsigned int col_count;
statement *ptr;
DYNAMIC_STRING update_string;
DBUG_ENTER("build_update_string");
@@ -818,14 +885,7 @@ build_update_string(void)
}
if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
- {
- if (snprintf(buf, HUGE_STRING_LENGTH, " WHERE id = ") > HUGE_STRING_LENGTH)
- {
- fprintf(stderr, "Memory Allocation error in creating update_string\n");
- exit(1);
- }
- dynstr_append(&update_string, buf);
- }
+ dynstr_append(&update_string, " WHERE id = ");
ptr= (statement *)my_malloc(sizeof(statement),
@@ -854,7 +914,7 @@ static statement *
build_insert_string(void)
{
char buf[HUGE_STRING_LENGTH];
- int col_count;
+ unsigned int col_count;
statement *ptr;
DYNAMIC_STRING insert_string;
DBUG_ENTER("build_insert_string");
@@ -865,12 +925,7 @@ build_insert_string(void)
if (auto_generate_sql_autoincrement)
{
- if (snprintf(buf, HUGE_STRING_LENGTH, "NULL") > HUGE_STRING_LENGTH)
- {
- fprintf(stderr, "Memory Allocation error in creating insert\n");
- exit(1);
- }
- dynstr_append(&insert_string, buf);
+ dynstr_append(&insert_string, "NULL");
if (num_int_cols || num_char_cols)
dynstr_append(&insert_string, ",");
@@ -878,12 +933,23 @@ build_insert_string(void)
if (auto_generate_sql_guid_primary)
{
- if (snprintf(buf, HUGE_STRING_LENGTH, "uuid()") > HUGE_STRING_LENGTH)
+ dynstr_append(&insert_string, "uuid()");
+
+ if (num_int_cols || num_char_cols)
+ dynstr_append(&insert_string, ",");
+ }
+
+ if (auto_generate_sql_secondary_indexes)
+ {
+ unsigned int count;
+
+ for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
{
- fprintf(stderr, "Memory Allocation error in create table\n");
- exit(1);
+ if (count) /* Except for the first pass we add a comma */
+ dynstr_append(&insert_string, ",");
+
+ dynstr_append(&insert_string, "uuid()");
}
- dynstr_append(&insert_string, buf);
if (num_int_cols || num_char_cols)
dynstr_append(&insert_string, ",");
@@ -939,7 +1005,7 @@ static statement *
build_select_string(my_bool key)
{
char buf[HUGE_STRING_LENGTH];
- int col_count;
+ unsigned int col_count;
statement *ptr;
static DYNAMIC_STRING query_string;
DBUG_ENTER("build_select_string");
@@ -1088,6 +1154,29 @@ get_options(int *argc,char ***argv)
if (opt_only_print)
opt_silent= TRUE;
+ if (num_int_cols_opt)
+ {
+ option_string *str;
+ parse_option(num_int_cols_opt, &str, ',');
+ num_int_cols= atoi(str->string);
+ if (str->option)
+ num_int_cols_index= atoi(str->option);
+ option_cleanup(str);
+ }
+
+ if (num_char_cols_opt)
+ {
+ option_string *str;
+ parse_option(num_char_cols_opt, &str, ',');
+ num_char_cols= atoi(str->string);
+ if (str->option)
+ num_char_cols_index= atoi(str->option);
+ else
+ num_char_cols_index= 0;
+ option_cleanup(str);
+ }
+
+
if (auto_generate_sql)
{
unsigned long long x= 0;
@@ -1253,7 +1342,7 @@ get_options(int *argc,char ***argv)
printf("Parsing engines to use.\n");
if (default_engine)
- parse_delimiter(default_engine, &engine_statements, ',');
+ parse_option(default_engine, &engine_options, ',');
if (tty_password)
opt_password= get_tty_password(NullS);
@@ -1276,10 +1365,8 @@ static int run_query(MYSQL *mysql, const char *query, int len)
static int
-generate_primary_key_list(MYSQL *mysql, statement *engine_stmt)
+generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt)
{
- char query[HUGE_STRING_LENGTH];
- int len;
MYSQL_RES *result;
MYSQL_ROW row;
unsigned long long counter;
@@ -1301,9 +1388,7 @@ generate_primary_key_list(MYSQL *mysql, statement *engine_stmt)
}
else
{
- len= snprintf(query, HUGE_STRING_LENGTH, "SELECT id from t1");
-
- if (run_query(mysql, query, len))
+ if (run_query(mysql, "SELECT id from t1", strlen("SELECT id from t1")))
{
fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", my_progname,
mysql_error(mysql));
@@ -1352,7 +1437,7 @@ drop_primary_key_list(void)
static int
create_schema(MYSQL *mysql, const char *db, statement *stmt,
- statement *engine_stmt)
+ option_string *engine_stmt)
{
char query[HUGE_STRING_LENGTH];
statement *ptr;
@@ -1411,11 +1496,27 @@ limit_not_met:
if (auto_generate_sql && ( auto_generate_sql_number == count))
break;
- if (run_query(mysql, ptr->string, ptr->length))
+ if (engine_stmt && engine_stmt->option && ptr->type == CREATE_TABLE_TYPE)
{
- fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
- my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
- exit(1);
+ char buffer[HUGE_STRING_LENGTH];
+
+ snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->string,
+ engine_stmt->option);
+ if (run_query(mysql, buffer, strlen(buffer)))
+ {
+ fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
+ my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
+ exit(1);
+ }
+ }
+ else
+ {
+ if (run_query(mysql, ptr->string, ptr->length))
+ {
+ fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
+ my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
+ exit(1);
+ }
}
}
@@ -1734,6 +1835,84 @@ end:
DBUG_RETURN(0);
}
+uint
+parse_option(const char *origin, option_string **stmt, char delm)
+{
+ char *retstr;
+ char *ptr= (char *)origin;
+ option_string **sptr= stmt;
+ option_string *tmp;
+ uint length= strlen(origin);
+ uint count= 0; /* We know that there is always one */
+
+ for (tmp= *sptr= (option_string *)my_malloc(sizeof(option_string),
+ MYF(MY_ZEROFILL|MY_FAE|MY_WME));
+ (retstr= strchr(ptr, delm));
+ tmp->next= (option_string *)my_malloc(sizeof(option_string),
+ MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
+ tmp= tmp->next)
+ {
+ char buffer[HUGE_STRING_LENGTH];
+ char *buffer_ptr;
+
+ count++;
+ strncpy(buffer, ptr, (size_t)(retstr - ptr));
+ if ((buffer_ptr= strchr(buffer, ':')))
+ {
+ char *option_ptr;
+
+ tmp->length= (size_t)(buffer_ptr - buffer);
+ tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE));
+
+ option_ptr= ptr + 1 + tmp->length;
+
+ /* Move past the : and the first string */
+ tmp->option_length= (size_t)(retstr - option_ptr);
+ tmp->option= my_strndup(option_ptr, tmp->option_length,
+ MYF(MY_FAE));
+ }
+ else
+ {
+ tmp->string= my_strndup(ptr, (size_t)(retstr - ptr), MYF(MY_FAE));
+ tmp->length= (size_t)(retstr - ptr);
+ }
+
+ ptr+= retstr - ptr + 1;
+ if (isspace(*ptr))
+ ptr++;
+ count++;
+ }
+
+ if (ptr != origin+length)
+ {
+ char *origin_ptr;
+
+ if ((origin_ptr= strchr(ptr, ':')))
+ {
+ char *option_ptr;
+
+ tmp->length= (size_t)(origin_ptr - ptr);
+ tmp->string= my_strndup(origin, tmp->length, MYF(MY_FAE));
+
+ option_ptr= (char *)ptr + 1 + tmp->length;
+
+ /* Move past the : and the first string */
+ tmp->option_length= (size_t)((ptr + length) - option_ptr);
+ tmp->option= my_strndup(option_ptr, tmp->option_length,
+ MYF(MY_FAE));
+ }
+ else
+ {
+ tmp->length= (size_t)((ptr + length) - ptr);
+ tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE));
+ }
+
+ count++;
+ }
+
+ return count;
+}
+
uint
parse_delimiter(const char *script, statement **stmt, char delm)
@@ -1821,9 +2000,11 @@ void
print_conclusions_csv(conclusions *con)
{
char buffer[HUGE_STRING_LENGTH];
+ const char *ptr= auto_generate_sql_type ? auto_generate_sql_type : "query";
snprintf(buffer, HUGE_STRING_LENGTH,
- "%s,query,%ld.%03ld,%ld.%03ld,%ld.%03ld,%d,%llu\n",
+ "%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%d,%llu\n",
con->engine ? con->engine : "", /* Storage engine we ran against */
+ ptr, /* Load type */
con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
con->min_timing / 1000, con->min_timing % 1000, /* Min time */
con->max_timing / 1000, con->max_timing % 1000, /* Max time */
@@ -1834,7 +2015,7 @@ print_conclusions_csv(conclusions *con)
}
void
-generate_stats(conclusions *con, statement *eng, stats *sptr)
+generate_stats(conclusions *con, option_string *eng, stats *sptr)
{
stats *ptr;
unsigned int x;
@@ -1867,6 +2048,24 @@ generate_stats(conclusions *con, statement *eng, stats *sptr)
}
void
+option_cleanup(option_string *stmt)
+{
+ option_string *ptr, *nptr;
+ if (!stmt)
+ return;
+
+ for (ptr= stmt; ptr; ptr= nptr)
+ {
+ nptr= ptr->next;
+ if (ptr->string)
+ my_free((gptr)ptr->string, MYF(0));
+ if (ptr->option)
+ my_free((gptr)ptr->option, MYF(0));
+ my_free((gptr)(byte *)ptr, MYF(0));
+ }
+}
+
+void
statement_cleanup(statement *stmt)
{
statement *ptr, *nptr;
diff --git a/mysql-test/t/mysqlslap.test b/mysql-test/t/mysqlslap.test
index 5d98dac03ea..f2bb9a72ecf 100644
--- a/mysql-test/t/mysqlslap.test
+++ b/mysql-test/t/mysqlslap.test
@@ -32,3 +32,5 @@
--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-guid-primary --auto-generate-sql-load-type=update --auto-generate-sql-execute-number=5
--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-guid-primary --auto-generate-sql-load-type=key --auto-generate-sql-execute-number=5
+
+--exec $MYSQL_SLAP --silent --concurrency=5 --iterations=1 --number-int-cols=2 --number-char-cols=3 --auto-generate-sql --auto-generate-sql-guid-primary --auto-generate-sql-load-type=key --auto-generate-sql-execute-number=5 --auto-generate-sql-secondary-indexes=3
diff --git a/sql/authors.h b/sql/authors.h
index 48b807c7884..dfe3b143e2f 100644
--- a/sql/authors.h
+++ b/sql/authors.h
@@ -66,6 +66,7 @@ struct show_table_authors_st show_table_authors[]= {
"Parser, port to OS/2, storage engines and some random stuff" },
{ "Yuri Dario", "", "OS/2 port" },
{ "Andrei Elkin", "Espoo, Finland", "Replication" },
+ { "Patrick Galbraith", "Sharon, NH", "Federated Engine, mysqlslap" },
{ "Sergei Golubchik", "Kerpen, Germany",
"Full-text search, precision math" },
{ "Lenz Grimmer", "Hamburg, Germany",