Commit 348d66d0 authored by Michael Widenius's avatar Michael Widenius

Fix for LP#571200 MySQL Bug#32426: FederatedX corrupt ORDER BY with TEXT

Patch taken from lp:~capttofu/maria/bug_571200 (originally for MariaDB 5.3, but adapted for 5.1)

parent 097977c0
......@@ -213,7 +213,7 @@ id name
alter server s1 options (database 'db_bogus');
flush tables;
select * from federated.t1;
ERROR 42000: Got error: 1044 : Access denied for user 'test_fed'@'localhost' to database 'db_bogus'
ERROR 42000: Received error: 1044 : Access denied for user 'test_fed'@'localhost' to database 'db_bogus'
drop server if exists 's1';
ERROR 42000: Access denied; you need the SUPER privilege for this operation
create server 's1' foreign data wrapper 'mysql' options
......
/*
/*
Copyright (c) 2007, Antony T Curtis
All rights reserved.
......@@ -51,6 +51,12 @@ typedef struct federatedx_savepoint
uint flags;
} SAVEPT;
struct mysql_position
{
MYSQL_RES* result;
MYSQL_ROW_OFFSET offset;
};
class federatedx_io_mysql :public federatedx_io
{
......@@ -76,16 +82,16 @@ class federatedx_io_mysql :public federatedx_io
virtual int error_code();
virtual const char *error_str();
void reset();
int commit();
int rollback();
int savepoint_set(ulong sp);
ulong savepoint_release(ulong sp);
ulong savepoint_rollback(ulong sp);
void savepoint_restrict(ulong sp);
ulong last_savepoint() const;
ulong actual_savepoint() const;
bool is_autocommit() const;
......@@ -94,7 +100,7 @@ class federatedx_io_mysql :public federatedx_io
uint table_name_length, uint flag);
/* resultset operations */
virtual void free_result(FEDERATEDX_IO_RESULT *io_result);
virtual unsigned int get_num_fields(FEDERATEDX_IO_RESULT *io_result);
virtual my_ulonglong get_num_rows(FEDERATEDX_IO_RESULT *io_result);
......@@ -104,6 +110,12 @@ class federatedx_io_mysql :public federatedx_io
unsigned int column);
virtual bool is_column_null(const FEDERATEDX_IO_ROW *row,
unsigned int column) const;
virtual size_t get_ref_length() const;
virtual void mark_position(FEDERATEDX_IO_RESULT *io_result,
void *ref);
virtual int seek_position(FEDERATEDX_IO_RESULT **io_result,
const void *ref);
};
......@@ -466,14 +478,13 @@ const char *federatedx_io_mysql::error_str()
return mysql_error(&mysql);
}
FEDERATEDX_IO_RESULT *federatedx_io_mysql::store_result()
{
FEDERATEDX_IO_RESULT *result;
DBUG_ENTER("federatedx_io_mysql::store_result");
result= (FEDERATEDX_IO_RESULT *) mysql_store_result(&mysql);
DBUG_RETURN(result);
}
......@@ -590,3 +601,45 @@ bool federatedx_io_mysql::table_metadata(ha_statistics *stats,
free_result(result);
return 1;
}
size_t federatedx_io_mysql::get_ref_length() const
{
return sizeof(mysql_position);
}
void federatedx_io_mysql::mark_position(FEDERATEDX_IO_RESULT *io_result,
void *ref)
{
MYSQL_ROWS *tmp= 0;
mysql_position& pos= *reinterpret_cast<mysql_position*>(ref);
pos.result= (MYSQL_RES *) io_result;
if (pos.result && pos.result->data)
{
for (tmp= pos.result->data->data;
tmp && (tmp->next != pos.result->data_cursor);
tmp= tmp->next)
{}
}
pos.offset= tmp;
}
int federatedx_io_mysql::seek_position(FEDERATEDX_IO_RESULT **io_result,
const void *ref)
{
const mysql_position& pos= *reinterpret_cast<const mysql_position*>(ref);
if (!pos.result || !pos.offset)
return HA_ERR_END_OF_FILE;
pos.result->current_row= 0;
pos.result->data_cursor= pos.offset;
*io_result= (FEDERATEDX_IO_RESULT*) pos.result;
return 0;
}
......@@ -96,6 +96,11 @@ class federatedx_io_null :public federatedx_io
unsigned int column);
virtual bool is_column_null(const FEDERATEDX_IO_ROW *row,
unsigned int column) const;
virtual size_t get_ref_length() const;
virtual void mark_position(FEDERATEDX_IO_RESULT *io_result,
void *ref);
virtual int seek_position(FEDERATEDX_IO_RESULT **io_result,
const void *ref);
};
......@@ -275,3 +280,20 @@ bool federatedx_io_null::table_metadata(ha_statistics *stats,
return 0;
}
size_t federatedx_io_null::get_ref_length() const
{
return sizeof(int);
}
void federatedx_io_null::mark_position(FEDERATEDX_IO_RESULT *io_result,
void *ref)
{
}
int federatedx_io_null::seek_position(FEDERATEDX_IO_RESULT **io_result,
const void *ref)
{
return 0;
}
This diff is collapsed.
/*
Copyright (c) 2008, Patrick Galbraith
/*
Copyright (c) 2008, Patrick Galbraith
All rights reserved.
Redistribution and use in source and binary forms, with or without
......@@ -43,7 +43,7 @@ class federatedx_io;
typedef struct st_fedrated_server {
MEM_ROOT mem_root;
uint use_count, io_count;
uchar *key;
uint key_length;
......@@ -74,10 +74,10 @@ typedef struct st_fedrated_server {
#include <mysql.h>
/*
/*
handler::print_error has a case statement for error numbers.
This value is (10000) is far out of range and will envoke the
default: case.
This value is (10000) is far out of range and will envoke the
default: case.
(Current error range is 120-159 from include/my_base.h)
*/
#define HA_FEDERATEDX_ERROR_WITH_REMOTE_SYSTEM 10000
......@@ -158,7 +158,7 @@ class federatedx_io
const char * get_database() const { return server->database; }
ushort get_port() const { return server->port; }
const char * get_socket() const { return server->socket; }
static bool handles_scheme(const char *scheme);
static federatedx_io *construct(MEM_ROOT *server_root,
FEDERATEDX_SERVER *server);
......@@ -167,7 +167,7 @@ class federatedx_io
{ return alloc_root(mem_root, size); }
static void operator delete(void *ptr, size_t size)
{ TRASH(ptr, size); }
virtual int query(const char *buffer, uint length)=0;
virtual FEDERATEDX_IO_RESULT *store_result()=0;
......@@ -178,25 +178,25 @@ class federatedx_io
virtual int error_code()=0;
virtual const char *error_str()=0;
virtual void reset()=0;
virtual int commit()=0;
virtual int rollback()=0;
virtual int savepoint_set(ulong sp)=0;
virtual ulong savepoint_release(ulong sp)=0;
virtual ulong savepoint_rollback(ulong sp)=0;
virtual void savepoint_restrict(ulong sp)=0;
virtual ulong last_savepoint() const=0;
virtual ulong actual_savepoint() const=0;
virtual bool is_autocommit() const=0;
virtual bool table_metadata(ha_statistics *stats, const char *table_name,
uint table_name_length, uint flag) = 0;
/* resultset operations */
virtual void free_result(FEDERATEDX_IO_RESULT *io_result)=0;
virtual unsigned int get_num_fields(FEDERATEDX_IO_RESULT *io_result)=0;
virtual my_ulonglong get_num_rows(FEDERATEDX_IO_RESULT *io_result)=0;
......@@ -206,6 +206,13 @@ class federatedx_io
unsigned int column)=0;
virtual bool is_column_null(const FEDERATEDX_IO_ROW *row,
unsigned int column) const=0;
virtual size_t get_ref_length() const=0;
virtual void mark_position(FEDERATEDX_IO_RESULT *io_result,
void *ref)=0;
virtual int seek_position(FEDERATEDX_IO_RESULT **io_result,
const void *ref)=0;
};
......@@ -215,12 +222,12 @@ class federatedx_txn
ulong savepoint_level;
ulong savepoint_stmt;
ulong savepoint_next;
void release_scan();
public:
federatedx_txn();
~federatedx_txn();
bool has_connections() const { return txn_list != NULL; }
bool in_transaction() const { return savepoint_next != 0; }
int acquire(FEDERATEDX_SHARE *share, bool readonly, federatedx_io **io);
......@@ -254,8 +261,12 @@ class ha_federatedx: public handler
federatedx_txn *txn;
federatedx_io *io;
FEDERATEDX_IO_RESULT *stored_result;
/**
Array of all stored results we get during a query execution.
*/
DYNAMIC_ARRAY results;
bool position_called;
uint fetch_num; // stores the fetch num
FEDERATEDX_IO_OFFSET current_position; // Current position used by ::position()
int remote_error_number;
char remote_error_buf[FEDERATEDX_QUERY_BUFFER_SIZE];
bool ignore_duplicates, replace_duplicates;
......@@ -269,7 +280,7 @@ class ha_federatedx: public handler
*/
uint convert_row_to_internal_format(uchar *buf, FEDERATEDX_IO_ROW *row,
FEDERATEDX_IO_RESULT *result);
bool create_where_from_key(String *to, KEY *key_info,
bool create_where_from_key(String *to, KEY *key_info,
const key_range *start_key,
const key_range *end_key,
bool records_in_range, bool eq_range);
......@@ -348,18 +359,18 @@ class ha_federatedx: public handler
Talk to Kostja about this - how to get the
number of rows * ...
disk scan time on other side (block size, size of the row) + network time ...
The reason for "records * 1000" is that such a large number forces
The reason for "records * 1000" is that such a large number forces
this to use indexes "
*/
double scan_time()
{
DBUG_PRINT("info", ("records %lu", (ulong) stats.records));
return (double)(stats.records*1000);
return (double)(stats.records*1000);
}
/*
The next method will never be called if you do not implement indexes.
*/
double read_time(uint index, uint ranges, ha_rows rows)
double read_time(uint index, uint ranges, ha_rows rows)
{
/*
Per Brian, this number is bugus, but this method must be implemented,
......
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