summaryrefslogtreecommitdiff
path: root/storage/federated/ha_federated.cc
diff options
context:
space:
mode:
authorunknown <knielsen@knielsen-hq.org>2010-04-28 14:52:24 +0200
committerunknown <knielsen@knielsen-hq.org>2010-04-28 14:52:24 +0200
commitb1e00b6be81c80b09d11085d77d86978e26df988 (patch)
treebb1fdd7363fbf2580572ac9a56dbd4c933cc4c0d /storage/federated/ha_federated.cc
parent1f683a7270e63abfadce20c6f51370621ff065e1 (diff)
parentc9cfd2df5f2f58c2cdf716999ebea252c307333f (diff)
downloadmariadb-git-b1e00b6be81c80b09d11085d77d86978e26df988.tar.gz
Merge MySQL 5.1.46 into MariaDB.
Still two test failures to be solved: main.myisam and main.subselect.
Diffstat (limited to 'storage/federated/ha_federated.cc')
-rw-r--r--storage/federated/ha_federated.cc208
1 files changed, 121 insertions, 87 deletions
diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc
index d9b1f1ffeeb..4330d9bdd30 100644
--- a/storage/federated/ha_federated.cc
+++ b/storage/federated/ha_federated.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2004 MySQL AB
+/* Copyright (c) 2004, 2010 Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -1253,7 +1253,7 @@ bool ha_federated::create_where_from_key(String *to,
const key_range *start_key,
const key_range *end_key,
bool from_records_in_range,
- bool eq_range)
+ bool eq_range_arg)
{
bool both_not_null=
(start_key != NULL && end_key != NULL) ? TRUE : FALSE;
@@ -1360,7 +1360,7 @@ bool ha_federated::create_where_from_key(String *to,
}
break;
case HA_READ_AFTER_KEY:
- if (eq_range)
+ if (eq_range_arg)
{
if (tmp.append("1=1")) // Dummy
goto err;
@@ -1621,11 +1621,10 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
DBUG_ASSERT(mysql == NULL);
- ref_length= (table->s->primary_key != MAX_KEY ?
- table->key_info[table->s->primary_key].key_length :
- table->s->reclength);
+ ref_length= sizeof(MYSQL_RES *) + sizeof(MYSQL_ROW_OFFSET);
DBUG_PRINT("info", ("ref_length: %u", ref_length));
+ my_init_dynamic_array(&results, sizeof(MYSQL_RES *), 4, 4);
reset();
DBUG_RETURN(0);
@@ -1645,21 +1644,17 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
int ha_federated::close(void)
{
- int retval;
DBUG_ENTER("ha_federated::close");
- /* free the result set */
- if (stored_result)
- {
- mysql_free_result(stored_result);
- stored_result= 0;
- }
+ free_result();
+
+ delete_dynamic(&results);
+
/* Disconnect from mysql */
mysql_close(mysql);
mysql= NULL;
- retval= free_share(share);
- DBUG_RETURN(retval);
+ DBUG_RETURN(free_share(share));
}
/*
@@ -2326,8 +2321,7 @@ int ha_federated::index_read(uchar *buf, const uchar *key,
{
DBUG_ENTER("ha_federated::index_read");
- if (stored_result)
- mysql_free_result(stored_result);
+ free_result();
DBUG_RETURN(index_read_idx_with_result_set(buf, active_index, key,
key_len, find_flag,
&stored_result));
@@ -2359,7 +2353,8 @@ int ha_federated::index_read_idx(uchar *buf, uint index, const uchar *key,
&mysql_result)))
DBUG_RETURN(retval);
mysql_free_result(mysql_result);
- DBUG_RETURN(retval);
+ results.elements--;
+ DBUG_RETURN(0);
}
@@ -2415,18 +2410,20 @@ int ha_federated::index_read_idx_with_result_set(uchar *buf, uint index,
retval= ER_QUERY_ON_FOREIGN_DATA_SOURCE;
goto error;
}
- if (!(*result= mysql_store_result(mysql)))
+ if (!(*result= store_result(mysql)))
{
retval= HA_ERR_END_OF_FILE;
goto error;
}
- if (!(retval= read_next(buf, *result)))
+ if ((retval= read_next(buf, *result)))
+ {
+ mysql_free_result(*result);
+ results.elements--;
+ *result= 0;
+ table->status= STATUS_NOT_FOUND;
DBUG_RETURN(retval);
-
- mysql_free_result(*result);
- *result= 0;
- table->status= STATUS_NOT_FOUND;
- DBUG_RETURN(retval);
+ }
+ DBUG_RETURN(0);
error:
table->status= STATUS_NOT_FOUND;
@@ -2486,12 +2483,6 @@ int ha_federated::read_range_first(const key_range *start_key,
create_where_from_key(&sql_query,
&table->key_info[active_index],
start_key, end_key, 0, eq_range_arg);
-
- if (stored_result)
- {
- mysql_free_result(stored_result);
- stored_result= 0;
- }
if (real_query(sql_query.ptr(), sql_query.length()))
{
retval= ER_QUERY_ON_FOREIGN_DATA_SOURCE;
@@ -2499,14 +2490,13 @@ int ha_federated::read_range_first(const key_range *start_key,
}
sql_query.length(0);
- if (!(stored_result= mysql_store_result(mysql)))
+ if (!(stored_result= store_result(mysql)))
{
retval= HA_ERR_END_OF_FILE;
goto error;
}
-
- retval= read_next(table->record[0], stored_result);
- DBUG_RETURN(retval);
+
+ DBUG_RETURN(read_next(table->record[0], stored_result));
error:
table->status= STATUS_NOT_FOUND;
@@ -2516,10 +2506,8 @@ error:
int ha_federated::read_range_next()
{
- int retval;
DBUG_ENTER("ha_federated::read_range_next");
- retval= rnd_next(table->record[0]);
- DBUG_RETURN(retval);
+ DBUG_RETURN(rnd_next(table->record[0]));
}
@@ -2585,23 +2573,11 @@ int ha_federated::rnd_init(bool scan)
if (scan)
{
- if (stored_result)
- {
- mysql_free_result(stored_result);
- stored_result= 0;
- }
-
- if (real_query(share->select_query, strlen(share->select_query)))
- goto error;
-
- stored_result= mysql_store_result(mysql);
- if (!stored_result)
- goto error;
+ if (real_query(share->select_query, strlen(share->select_query)) ||
+ !(stored_result= store_result(mysql)))
+ DBUG_RETURN(stash_remote_error());
}
DBUG_RETURN(0);
-
-error:
- DBUG_RETURN(stash_remote_error());
}
@@ -2615,11 +2591,7 @@ int ha_federated::rnd_end()
int ha_federated::index_end(void)
{
DBUG_ENTER("ha_federated::index_end");
- if (stored_result)
- {
- mysql_free_result(stored_result);
- stored_result= 0;
- }
+ free_result();
active_index= MAX_KEY;
DBUG_RETURN(0);
}
@@ -2679,6 +2651,9 @@ int ha_federated::read_next(uchar *buf, MYSQL_RES *result)
DBUG_ENTER("ha_federated::read_next");
table->status= STATUS_NOT_FOUND; // For easier return
+
+ /* Save current data cursor position. */
+ current_position= result->data_cursor;
/* Fetch a row, insert it back in a row format. */
if (!(row= mysql_fetch_row(result)))
@@ -2691,24 +2666,38 @@ int ha_federated::read_next(uchar *buf, MYSQL_RES *result)
}
-/*
- store reference to current row so that we can later find it for
- a re-read, update or delete.
-
- In case of federated, a reference is either a primary key or
- the whole record.
-
- Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc.
+/**
+ @brief Store a reference to current row.
+
+ @details During a query execution we may have different result sets (RS),
+ e.g. for different ranges. All the RS's used are stored in
+ memory and placed in @c results dynamic array. At the end of
+ execution all stored RS's are freed at once in the
+ @c ha_federated::reset().
+ So, in case of federated, a reference to current row is a
+ stored result address and current data cursor position.
+ As we keep all RS in memory during a query execution,
+ we can get any record using the reference any time until
+ @c ha_federated::reset() is called.
+ TODO: we don't have to store all RS's rows but only those
+ we call @c ha_federated::position() for, so we can free memory
+ where we store other rows in the @c ha_federated::index_end().
+
+ @param[in] record record data (unused)
*/
-void ha_federated::position(const uchar *record)
+void ha_federated::position(const uchar *record __attribute__ ((unused)))
{
DBUG_ENTER("ha_federated::position");
- if (table->s->primary_key != MAX_KEY)
- key_copy(ref, (uchar *)record, table->key_info + table->s->primary_key,
- ref_length);
- else
- memcpy(ref, record, ref_length);
+
+ DBUG_ASSERT(stored_result);
+
+ position_called= TRUE;
+ /* Store result set address. */
+ memcpy_fixed(ref, &stored_result, sizeof(MYSQL_RES *));
+ /* Store data cursor position. */
+ memcpy_fixed(ref + sizeof(MYSQL_RES *), &current_position,
+ sizeof(MYSQL_ROW_OFFSET));
DBUG_VOID_RETURN;
}
@@ -2724,23 +2713,19 @@ void ha_federated::position(const uchar *record)
int ha_federated::rnd_pos(uchar *buf, uchar *pos)
{
- int result;
+ MYSQL_RES *result;
DBUG_ENTER("ha_federated::rnd_pos");
+
ha_statistic_increment(&SSV::ha_read_rnd_count);
- if (table->s->primary_key != MAX_KEY)
- {
- /* We have a primary key, so use index_read_idx to find row */
- result= index_read_idx(buf, table->s->primary_key, pos,
- ref_length, HA_READ_KEY_EXACT);
- }
- else
- {
- /* otherwise, get the old record ref as obtained in ::position */
- memcpy(buf, pos, ref_length);
- result= 0;
- }
- table->status= result ? STATUS_NOT_FOUND : 0;
- DBUG_RETURN(result);
+
+ /* Get stored result set. */
+ memcpy_fixed(&result, pos, sizeof(MYSQL_RES *));
+ DBUG_ASSERT(result);
+ /* Set data cursor position. */
+ memcpy_fixed(&result->data_cursor, pos + sizeof(MYSQL_RES *),
+ sizeof(MYSQL_ROW_OFFSET));
+ /* Read a row. */
+ DBUG_RETURN(read_next(buf, result));
}
@@ -2943,6 +2928,16 @@ int ha_federated::reset(void)
insert_dup_update= FALSE;
ignore_duplicates= FALSE;
replace_duplicates= FALSE;
+
+ /* Free stored result sets. */
+ for (uint i= 0; i < results.elements; i++)
+ {
+ MYSQL_RES *result;
+ get_dynamic(&results, (uchar *) &result, i);
+ mysql_free_result(result);
+ }
+ reset_dynamic(&results);
+
return 0;
}
@@ -3206,6 +3201,45 @@ bool ha_federated::get_error_message(int error, String* buf)
DBUG_RETURN(FALSE);
}
+
+/**
+ @brief Store a result set.
+
+ @details Call @c mysql_store_result() to save a result set then
+ append it to the stored results array.
+
+ @param[in] mysql_arg MySLQ connection structure.
+
+ @return Stored result set (MYSQL_RES object).
+*/
+
+MYSQL_RES *ha_federated::store_result(MYSQL *mysql_arg)
+{
+ MYSQL_RES *result= mysql_store_result(mysql_arg);
+ DBUG_ENTER("ha_federated::store_result");
+ if (result)
+ {
+ (void) insert_dynamic(&results, (uchar*) &result);
+ }
+ position_called= FALSE;
+ DBUG_RETURN(result);
+}
+
+
+void ha_federated::free_result()
+{
+ DBUG_ENTER("ha_federated::free_result");
+ if (stored_result && !position_called)
+ {
+ mysql_free_result(stored_result);
+ stored_result= 0;
+ if (results.elements > 0)
+ results.elements--;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
int ha_federated::external_lock(THD *thd, int lock_type)
{
int error= 0;