Merge lp:~capttofu/maria/bug_571200 into lp:maria/5.3

Proposed by CaptTofu
Status: Needs review
Proposed branch: lp:~capttofu/maria/bug_571200
Merge into: lp:maria/5.3
Diff against target: 784 lines (+308/-104)
7 files modified
mysql-test/suite/federated/federated_bug_32426.result (+30/-0)
mysql-test/suite/federated/federated_bug_32426.test (+24/-0)
storage/federated/ha_federated.cc (+1/-1)
storage/federatedx/federatedx_io_mysql.cc (+60/-8)
storage/federatedx/federatedx_io_null.cc (+22/-0)
storage/federatedx/ha_federatedx.cc (+140/-75)
storage/federatedx/ha_federatedx.h (+31/-20)
To merge this branch: bzr merge lp:~capttofu/maria/bug_571200
Reviewer Review Type Date Requested Status
Maria-captains Pending
Review via email: mp+31606@code.launchpad.net

Description of the change

revno: 2804
committer: Patrick Galbraith <patg@patg-desktop>
branch nick: maria-stock
timestamp: Fri 2010-07-23 15:37:32 -0400
message:
  Maria BUG# 571200, MySQL BUG# 32426: Fixed BLOG column order by for FederatedX

  Applied Antony's fixes to what I had started. These fixes were from his
  multi-bug fix at
  http://bazaar.launchpad.net/~atcurtis/maria/federatedx/revision/2833
  and are only the fixes for the ORDER BY BUG. I will also add separately the
  other fixes per-bug

  * Merged in fix for MySQL Bug#32426, http://lists.mysql.com/commits/102419
    However the io back-end is seperated from the front-end.
  * Added 3 new methods for the i/o class to abstract result set cursor
    positioning. Note to future self pertaining to IO subclasses for other
    drivers such as ODBC
  * Added test 'federated_bug_32426' to suite.

  https://bugs.launchpad.net/maria/+bug/571200

To post a comment you must log in.
Revision history for this message
Michael Widenius (monty) wrote :

Hi!

>>>>> "CaptTofu" == CaptTofu <email address hidden> writes:

CaptTofu> CaptTofu has proposed merging lp:~capttofu/maria/bug_571200 into lp:maria.
CaptTofu> Requested reviews:
CaptTofu> Maria-captains (maria-captains)
CaptTofu> Related bugs:
CaptTofu> #571200 MySQL Bug#32426: FederatedX corrupt ORDER BY with TEXT
CaptTofu> https://bugs.launchpad.net/bugs/571200

Great!

I will review this tomorrow and if ok pull it into 5.1

Regards,
Monty

Revision history for this message
Michael Widenius (monty) wrote :

I was looking at merging this to 5.1 to fix the open federated bugs in 5.1, but the tree is depending on 5.2

i will look at this next week (after linuxconf) and see if I can easily extract the patch and apply it safely to 5.1

Unmerged revisions

2804. By Patrick Galbraith <patg@patg-desktop>

Maria BUG# 571200, MySQL BUG# 32426: Fixed BLOG column order by for FederatedX

Applied Antony's fixes to what I had started. These fixes were from his
multi-bug fix at
http://bazaar.launchpad.net/~atcurtis/maria/federatedx/revision/2833
and are only the fixes for the ORDER BY BUG. I will also add separately the
other fixes per-bug

* Merged in fix for MySQL Bug#32426, http://lists.mysql.com/commits/102419
  However the io back-end is seperated from the front-end.
* Added 3 new methods for the i/o class to abstract result set cursor
  positioning. Note to future self pertaining to IO subclasses for other
  drivers such as ODBC
* Added test 'federated_bug_32426' to suite.

https://bugs.launchpad.net/maria/+bug/571200

2803. By Patrick Galbraith <patg@patg-desktop>

Work in progress with federated_io methods

2802. By Patrick Galbraith <patg@patg-desktop>

Work in progress on adding federatedx_io methods

Methods for result set and result set positions

2801. By Patrick Galbraith <patg@patg-desktop>

Work in progress fixing bug 571200.

Most of patch from http://lists.mysql.com/commits/102419 has been
integrated into FederatedX. Need to figure out how to set/get the
results->data_cursor to work with FEDERATEDX_IO_RESULT struct.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'mysql-test/suite/federated/federated_bug_32426.result'
2--- mysql-test/suite/federated/federated_bug_32426.result 1970-01-01 00:00:00 +0000
3+++ mysql-test/suite/federated/federated_bug_32426.result 2010-08-03 05:44:49 +0000
4@@ -0,0 +1,30 @@
5+CREATE DATABASE federated;
6+CREATE DATABASE federated;
7+#
8+# Bug #32426: FEDERATED query returns corrupt results for ORDER BY
9+# on a TEXT column
10+#
11+CREATE TABLE federated.t1(a TEXT);
12+INSERT INTO federated.t1 VALUES('abc'), ('gh'), ('f'), ('ijk'), ('de');
13+CREATE TABLE federated.t1(a TEXT) ENGINE=FEDERATED
14+CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
15+SELECT * FROM federated.t1 ORDER BY A;
16+a
17+abc
18+de
19+f
20+gh
21+ijk
22+SELECT * FROM federated.t1 ORDER BY A DESC;
23+a
24+ijk
25+gh
26+f
27+de
28+abc
29+DROP TABLE federated.t1;
30+DROP TABLE federated.t1;
31+DROP TABLE IF EXISTS federated.t1;
32+DROP DATABASE IF EXISTS federated;
33+DROP TABLE IF EXISTS federated.t1;
34+DROP DATABASE IF EXISTS federated;
35
36=== added file 'mysql-test/suite/federated/federated_bug_32426.test'
37--- mysql-test/suite/federated/federated_bug_32426.test 1970-01-01 00:00:00 +0000
38+++ mysql-test/suite/federated/federated_bug_32426.test 2010-08-03 05:44:49 +0000
39@@ -0,0 +1,24 @@
40+source federated.inc;
41+
42+--echo #
43+--echo # Bug #32426: FEDERATED query returns corrupt results for ORDER BY
44+--echo # on a TEXT column
45+--echo #
46+connection slave;
47+CREATE TABLE federated.t1(a TEXT);
48+INSERT INTO federated.t1 VALUES('abc'), ('gh'), ('f'), ('ijk'), ('de');
49+
50+connection master;
51+--replace_result $SLAVE_MYPORT SLAVE_PORT
52+eval CREATE TABLE federated.t1(a TEXT) ENGINE=FEDERATED
53+ CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
54+SELECT * FROM federated.t1 ORDER BY A;
55+SELECT * FROM federated.t1 ORDER BY A DESC;
56+DROP TABLE federated.t1;
57+
58+connection slave;
59+DROP TABLE federated.t1;
60+
61+connection default;
62+
63+source federated_cleanup.inc;
64
65=== modified file 'storage/federated/ha_federated.cc'
66--- storage/federated/ha_federated.cc 2010-06-01 19:52:20 +0000
67+++ storage/federated/ha_federated.cc 2010-08-03 05:44:49 +0000
68@@ -941,7 +941,7 @@
69 static bool emit_key_part_name(String *to, KEY_PART_INFO *part)
70 {
71 DBUG_ENTER("emit_key_part_name");
72- if (append_ident(to, part->field->field_name,
73+ if (append_ident(to, part->field->field_name,
74 strlen(part->field->field_name), ident_quote_char))
75 DBUG_RETURN(1); // Out of memory
76 DBUG_RETURN(0);
77
78=== modified file 'storage/federatedx/federatedx_io_mysql.cc'
79--- storage/federatedx/federatedx_io_mysql.cc 2009-11-14 19:33:59 +0000
80+++ storage/federatedx/federatedx_io_mysql.cc 2010-08-03 05:44:49 +0000
81@@ -1,4 +1,4 @@
82-/*
83+/*
84 Copyright (c) 2007, Antony T Curtis
85 All rights reserved.
86
87@@ -51,6 +51,12 @@
88 uint flags;
89 } SAVEPT;
90
91+struct mysql_position
92+{
93+ MYSQL_RES* result;
94+ MYSQL_ROW_OFFSET offset;
95+};
96+
97
98 class federatedx_io_mysql :public federatedx_io
99 {
100@@ -76,16 +82,16 @@
101
102 virtual int error_code();
103 virtual const char *error_str();
104-
105+
106 void reset();
107 int commit();
108 int rollback();
109-
110+
111 int savepoint_set(ulong sp);
112 ulong savepoint_release(ulong sp);
113 ulong savepoint_rollback(ulong sp);
114 void savepoint_restrict(ulong sp);
115-
116+
117 ulong last_savepoint() const;
118 ulong actual_savepoint() const;
119 bool is_autocommit() const;
120@@ -94,7 +100,7 @@
121 uint table_name_length, uint flag);
122
123 /* resultset operations */
124-
125+
126 virtual void free_result(FEDERATEDX_IO_RESULT *io_result);
127 virtual unsigned int get_num_fields(FEDERATEDX_IO_RESULT *io_result);
128 virtual my_ulonglong get_num_rows(FEDERATEDX_IO_RESULT *io_result);
129@@ -104,6 +110,12 @@
130 unsigned int column);
131 virtual bool is_column_null(const FEDERATEDX_IO_ROW *row,
132 unsigned int column) const;
133+
134+ virtual size_t get_ref_length() const;
135+ virtual void mark_position(FEDERATEDX_IO_RESULT *io_result,
136+ void *ref);
137+ virtual int seek_position(FEDERATEDX_IO_RESULT **io_result,
138+ const void *ref);
139 };
140
141
142@@ -466,14 +478,13 @@
143 return mysql_error(&mysql);
144 }
145
146-
147 FEDERATEDX_IO_RESULT *federatedx_io_mysql::store_result()
148 {
149 FEDERATEDX_IO_RESULT *result;
150 DBUG_ENTER("federatedx_io_mysql::store_result");
151-
152+
153 result= (FEDERATEDX_IO_RESULT *) mysql_store_result(&mysql);
154-
155+
156 DBUG_RETURN(result);
157 }
158
159@@ -590,3 +601,44 @@
160 free_result(result);
161 return 1;
162 }
163+
164+
165+
166+size_t federatedx_io_mysql::get_ref_length() const
167+{
168+ return sizeof(mysql_position);
169+}
170+
171+
172+void federatedx_io_mysql::mark_position(FEDERATEDX_IO_RESULT *io_result,
173+ void *ref)
174+{
175+ MYSQL_ROWS *tmp= 0;
176+ mysql_position& pos= *reinterpret_cast<mysql_position*>(ref);
177+ pos.result= (MYSQL_RES *) io_result;
178+
179+ if (pos.result && pos.result->data)
180+ {
181+ for (tmp= pos.result->data->data;
182+ tmp && (tmp->next != pos.result->data_cursor);
183+ tmp= tmp->next) ;
184+ }
185+
186+ pos.offset= tmp;
187+}
188+
189+int federatedx_io_mysql::seek_position(FEDERATEDX_IO_RESULT **io_result,
190+ const void *ref)
191+{
192+ const mysql_position& pos= *reinterpret_cast<const mysql_position*>(ref);
193+
194+ if (!pos.result || !pos.offset)
195+ return HA_ERR_END_OF_FILE;
196+
197+ pos.result->current_row= 0;
198+ pos.result->data_cursor= pos.offset;
199+ *io_result= (FEDERATEDX_IO_RESULT*) pos.result;
200+
201+ return 0;
202+}
203+
204
205=== modified file 'storage/federatedx/federatedx_io_null.cc'
206--- storage/federatedx/federatedx_io_null.cc 2009-11-14 19:33:59 +0000
207+++ storage/federatedx/federatedx_io_null.cc 2010-08-03 05:44:49 +0000
208@@ -96,6 +96,11 @@
209 unsigned int column);
210 virtual bool is_column_null(const FEDERATEDX_IO_ROW *row,
211 unsigned int column) const;
212+ virtual size_t get_ref_length() const;
213+ virtual void mark_position(FEDERATEDX_IO_RESULT *io_result,
214+ void *ref);
215+ virtual int seek_position(FEDERATEDX_IO_RESULT **io_result,
216+ const void *ref);
217 };
218
219
220@@ -275,3 +280,20 @@
221
222 return 0;
223 }
224+
225+size_t federatedx_io_null::get_ref_length() const
226+{
227+ return sizeof(int);
228+}
229+
230+
231+void federatedx_io_null::mark_position(FEDERATEDX_IO_RESULT *io_result,
232+ void *ref)
233+{
234+}
235+
236+int federatedx_io_null::seek_position(FEDERATEDX_IO_RESULT **io_result,
237+ const void *ref)
238+{
239+ return 0;
240+}
241
242=== modified file 'storage/federatedx/ha_federatedx.cc'
243--- storage/federatedx/ha_federatedx.cc 2010-04-01 14:34:51 +0000
244+++ storage/federatedx/ha_federatedx.cc 2010-08-03 05:44:49 +0000
245@@ -1717,14 +1717,14 @@
246 return *txnp;
247 }
248
249-
250+
251 int ha_federatedx::disconnect(handlerton *hton, MYSQL_THD thd)
252 {
253 federatedx_txn *txn= (federatedx_txn *) thd_get_ha_data(thd, hton);
254 delete txn;
255 return 0;
256 }
257-
258+
259
260 /*
261 Used for opening tables. The name will be the name of the file.
262@@ -1756,14 +1756,15 @@
263 free_share(txn, share);
264 DBUG_RETURN(error);
265 }
266-
267+
268+ ref_length= io->get_ref_length();
269+
270 txn->release(&io);
271-
272- ref_length= (table->s->primary_key != MAX_KEY ?
273- table->key_info[table->s->primary_key].key_length :
274- table->s->reclength);
275+
276 DBUG_PRINT("info", ("ref_length: %u", ref_length));
277
278+ my_init_dynamic_array(&results, sizeof(FEDERATEDX_IO_RESULT*), 4, 4);
279+
280 reset();
281
282 DBUG_RETURN(0);
283@@ -1788,8 +1789,7 @@
284 DBUG_ENTER("ha_federatedx::close");
285
286 /* free the result set */
287- if (stored_result)
288- retval= free_result();
289+ reset();
290
291 /* Disconnect from mysql */
292 if (!thd || !(txn= get_txn(thd, true)))
293@@ -1799,7 +1799,7 @@
294 tmp_txn.release(&io);
295
296 DBUG_ASSERT(io == NULL);
297-
298+
299 if ((error= free_share(&tmp_txn, share)))
300 retval= error;
301 }
302@@ -2525,7 +2525,7 @@
303 uint key_len, enum ha_rkey_function find_flag)
304 {
305 int retval;
306- FEDERATEDX_IO_RESULT *io_result;
307+ FEDERATEDX_IO_RESULT *io_result= 0;
308 DBUG_ENTER("ha_federatedx::index_read_idx");
309
310 if ((retval= index_read_idx_with_result_set(buf, index, key,
311@@ -2601,7 +2601,7 @@
312 if (!(retval= read_next(buf, *result)))
313 DBUG_RETURN(retval);
314
315- io->free_result(*result);
316+ insert_dynamic(&results, (uchar*) result);
317 *result= 0;
318 table->status= STATUS_NOT_FOUND;
319 DBUG_RETURN(retval);
320@@ -2669,10 +2669,7 @@
321 DBUG_RETURN(retval);
322
323 if (stored_result)
324- {
325- io->free_result(stored_result);
326- stored_result= 0;
327- }
328+ (void) free_result();
329
330 if (io->query(sql_query.ptr(), sql_query.length()))
331 {
332@@ -2773,10 +2770,7 @@
333 DBUG_RETURN(error);
334
335 if (stored_result)
336- {
337- io->free_result(stored_result);
338- stored_result= 0;
339- }
340+ (void) free_result();
341
342 if (io->query(share->select_query,
343 strlen(share->select_query)))
344@@ -2803,17 +2797,35 @@
345 int ha_federatedx::free_result()
346 {
347 int error;
348- federatedx_io *tmp_io= 0, **iop;
349+ DBUG_ENTER("ha_federatedx::free_result");
350 DBUG_ASSERT(stored_result);
351- if (!*(iop= &io) && (error= txn->acquire(share, TRUE, (iop= &tmp_io))))
352- {
353- DBUG_ASSERT(0); // Fail when testing
354- return error;
355- }
356- (*iop)->free_result(stored_result);
357+ for (uint i= 0; i < results.elements; ++i)
358+ {
359+ FEDERATEDX_IO_RESULT *result= 0;
360+ get_dynamic(&results, (uchar*) &result, i);
361+ if (result == stored_result)
362+ goto end;
363+ }
364+ if (position_called)
365+ {
366+ insert_dynamic(&results, (uchar*) &stored_result);
367+ }
368+ else
369+ {
370+ federatedx_io *tmp_io= 0, **iop;
371+ if (!*(iop= &io) && (error= txn->acquire(share, TRUE, (iop= &tmp_io))))
372+ {
373+ DBUG_ASSERT(0); // Fail when testing
374+ insert_dynamic(&results, (uchar*) &stored_result);
375+ goto end;
376+ }
377+ (*iop)->free_result(stored_result);
378+ txn->release(&tmp_io);
379+ }
380+end:
381 stored_result= 0;
382- txn->release(&tmp_io);
383- return 0;
384+ position_called= FALSE;
385+ DBUG_RETURN(0);
386 }
387
388 int ha_federatedx::index_end(void)
389@@ -2862,8 +2874,8 @@
390
391 SYNOPSIS
392 field_in_record_is_null()
393- buf byte pointer to record
394- result mysql result set
395+ buf byte pointer to record
396+ result mysql result set
397
398 DESCRIPTION
399 This method is a wrapper method that reads one record from a result
400@@ -2896,24 +2908,43 @@
401 }
402
403
404-/*
405- store reference to current row so that we can later find it for
406- a re-read, update or delete.
407-
408- In case of federatedx, a reference is either a primary key or
409- the whole record.
410-
411- Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc.
412+/**
413+ @brief Store a reference to current row.
414+
415+ @details During a query execution we may have different result sets (RS),
416+ e.g. for different ranges. All the RS's used are stored in
417+ memory and placed in @c results dynamic array. At the end of
418+ execution all stored RS's are freed at once in the
419+ @c ha_federated::reset().
420+ So, in case of federated, a reference to current row is a
421+ stored result address and current data cursor position.
422+ As we keep all RS in memory during a query execution,
423+ we can get any record using the reference any time until
424+ @c ha_federated::reset() is called.
425+ TODO: we don't have to store all RS's rows but only those
426+ we call @c ha_federated::position() for, so we can free memory
427+ where we store other rows in the @c ha_federated::index_end().
428+
429+ @param[in] record record data (unused)
430+
431 */
432
433-void ha_federatedx::position(const uchar *record)
434+void ha_federatedx::position(const uchar *record __attribute__ ((unused)))
435 {
436 DBUG_ENTER("ha_federatedx::position");
437- if (table->s->primary_key != MAX_KEY)
438- key_copy(ref, (uchar *)record, table->key_info + table->s->primary_key,
439- ref_length);
440- else
441- memcpy(ref, record, ref_length);
442+
443+ bzero(ref, ref_length);
444+
445+ if (!stored_result)
446+ DBUG_VOID_RETURN;
447+
448+ if (txn->acquire(share, TRUE, &io))
449+ DBUG_VOID_RETURN;
450+
451+ io->mark_position(stored_result, ref);
452+
453+ position_called= TRUE;
454+
455 DBUG_VOID_RETURN;
456 }
457
458@@ -2929,23 +2960,23 @@
459
460 int ha_federatedx::rnd_pos(uchar *buf, uchar *pos)
461 {
462- int result;
463+ int retval;
464+ FEDERATEDX_IO_RESULT *result= stored_result;
465 DBUG_ENTER("ha_federatedx::rnd_pos");
466 ha_statistic_increment(&SSV::ha_read_rnd_count);
467- if (table->s->primary_key != MAX_KEY)
468- {
469- /* We have a primary key, so use index_read_idx to find row */
470- result= index_read_idx(buf, table->s->primary_key, pos,
471- ref_length, HA_READ_KEY_EXACT);
472- }
473- else
474- {
475- /* otherwise, get the old record ref as obtained in ::position */
476- memcpy(buf, pos, ref_length);
477- result= 0;
478- }
479- table->status= result ? STATUS_NOT_FOUND : 0;
480- DBUG_RETURN(result);
481+
482+ if ((retval= txn->acquire(share, TRUE, &io)))
483+ goto error;
484+
485+ if ((retval= io->seek_position(&result, pos)))
486+ goto error;
487+
488+ retval= read_next(buf, result);
489+ DBUG_RETURN(retval);
490+
491+error:
492+ table->status= STATUS_NOT_FOUND;
493+ DBUG_RETURN(retval);
494 }
495
496
497@@ -2995,17 +3026,21 @@
498
499 int ha_federatedx::info(uint flag)
500 {
501- char error_buffer[FEDERATEDX_QUERY_BUFFER_SIZE];
502 uint error_code;
503+ THD *thd= current_thd;
504+ federatedx_txn *tmp_txn;
505 federatedx_io *tmp_io= 0, **iop= 0;
506 DBUG_ENTER("ha_federatedx::info");
507
508 error_code= ER_QUERY_ON_FOREIGN_DATA_SOURCE;
509-
510+
511+ // external_lock may not have been called so txn may not be set
512+ tmp_txn= get_txn(thd);
513+
514 /* we want not to show table status if not needed to do so */
515 if (flag & (HA_STATUS_VARIABLE | HA_STATUS_CONST | HA_STATUS_AUTO))
516 {
517- if (!*(iop= &io) && (error_code= txn->acquire(share, TRUE, (iop= &tmp_io))))
518+ if (!*(iop= &io) && (error_code= tmp_txn->acquire(share, TRUE, (iop= &tmp_io))))
519 goto fail;
520 }
521
522@@ -3030,25 +3065,23 @@
523 If ::info created it's own transaction, close it. This happens in case
524 of show table status;
525 */
526- txn->release(&tmp_io);
527+ tmp_txn->release(&tmp_io);
528
529 DBUG_RETURN(0);
530
531 error:
532 if (iop && *iop)
533 {
534- my_sprintf(error_buffer, (error_buffer, ": %d : %s",
535- (*iop)->error_code(), (*iop)->error_str()));
536- my_error(error_code, MYF(0), error_buffer);
537+ my_printf_error((*iop)->error_code(), "Received error: %d : %s", MYF(0),
538+ (*iop)->error_code(), (*iop)->error_str());
539 }
540- else
541- if (remote_error_number != -1 /* error already reported */)
542+ else if (remote_error_number != -1 /* error already reported */)
543 {
544 error_code= remote_error_number;
545 my_error(error_code, MYF(0), ER(error_code));
546 }
547 fail:
548- txn->release(&tmp_io);
549+ tmp_txn->release(&tmp_io);
550 DBUG_RETURN(error_code);
551 }
552
553@@ -3105,13 +3138,45 @@
554
555 int ha_federatedx::reset(void)
556 {
557+ int error = 0;
558+
559 insert_dup_update= FALSE;
560 ignore_duplicates= FALSE;
561 replace_duplicates= FALSE;
562- return 0;
563+ position_called= FALSE;
564+
565+ if (stored_result)
566+ insert_dynamic(&results, (uchar*) &stored_result);
567+ stored_result= 0;
568+
569+ if (results.elements)
570+ {
571+ federatedx_txn *tmp_txn;
572+ federatedx_io *tmp_io= 0, **iop;
573+
574+ // external_lock may not have been called so txn may not be set
575+ tmp_txn= get_txn(current_thd);
576+
577+ if (!*(iop= &io) && (error= tmp_txn->acquire(share, TRUE, (iop= &tmp_io))))
578+ {
579+ DBUG_ASSERT(0); // Fail when testing
580+ return error;
581+ }
582+
583+ for (uint i= 0; i < results.elements; ++i)
584+ {
585+ FEDERATEDX_IO_RESULT *result= 0;
586+ get_dynamic(&results, (uchar*) &result, i);
587+ (*iop)->free_result(result);
588+ }
589+ tmp_txn->release(&tmp_io);
590+ reset_dynamic(&results);
591+ }
592+
593+ return error;
594+
595 }
596
597-
598 /*
599 Used to delete all rows in a table. Both for cases of truncate and
600 for cases where the optimizer realizes that all rows will be
601@@ -3237,7 +3302,7 @@
602
603 str.length(0);
604 str.append(STRING_WITH_LEN("SELECT * FROM "));
605- append_identifier(thd, &str, share->table_name,
606+ append_identifier(thd, &str, share->table_name,
607 share->table_name_length);
608 str.append(STRING_WITH_LEN(" WHERE 1=0"));
609
610@@ -3288,14 +3353,14 @@
611 pthread_mutex_lock(&federatedx_mutex);
612 tmp_share.s= get_server(&tmp_share, NULL);
613 pthread_mutex_unlock(&federatedx_mutex);
614-
615+
616 if (tmp_share.s)
617 {
618 tmp_txn= get_txn(thd);
619 if (!(retval= tmp_txn->acquire(&tmp_share, TRUE, &tmp_io)))
620 {
621 retval= test_connection(thd, tmp_io, &tmp_share);
622- tmp_txn->release(&tmp_io);
623+ tmp_txn->release(&tmp_io);
624 }
625 free_server(tmp_txn, tmp_share.s);
626 }
627
628=== modified file 'storage/federatedx/ha_federatedx.h'
629--- storage/federatedx/ha_federatedx.h 2009-11-14 19:33:59 +0000
630+++ storage/federatedx/ha_federatedx.h 2010-08-03 05:44:49 +0000
631@@ -1,5 +1,5 @@
632-/*
633-Copyright (c) 2008, Patrick Galbraith
634+/*
635+Copyright (c) 2008, Patrick Galbraith
636 All rights reserved.
637
638 Redistribution and use in source and binary forms, with or without
639@@ -43,7 +43,7 @@
640 typedef struct st_fedrated_server {
641 MEM_ROOT mem_root;
642 uint use_count, io_count;
643-
644+
645 uchar *key;
646 uint key_length;
647
648@@ -74,10 +74,10 @@
649
650 #include <mysql.h>
651
652-/*
653+/*
654 handler::print_error has a case statement for error numbers.
655- This value is (10000) is far out of range and will envoke the
656- default: case.
657+ This value is (10000) is far out of range and will envoke the
658+ default: case.
659 (Current error range is 120-159 from include/my_base.h)
660 */
661 #define HA_FEDERATEDX_ERROR_WITH_REMOTE_SYSTEM 10000
662@@ -158,7 +158,7 @@
663 const char * get_database() const { return server->database; }
664 ushort get_port() const { return server->port; }
665 const char * get_socket() const { return server->socket; }
666-
667+
668 static bool handles_scheme(const char *scheme);
669 static federatedx_io *construct(MEM_ROOT *server_root,
670 FEDERATEDX_SERVER *server);
671@@ -167,7 +167,7 @@
672 { return alloc_root(mem_root, size); }
673 static void operator delete(void *ptr, size_t size)
674 { TRASH(ptr, size); }
675-
676+
677 virtual int query(const char *buffer, uint length)=0;
678 virtual FEDERATEDX_IO_RESULT *store_result()=0;
679
680@@ -178,25 +178,25 @@
681
682 virtual int error_code()=0;
683 virtual const char *error_str()=0;
684-
685+
686 virtual void reset()=0;
687 virtual int commit()=0;
688 virtual int rollback()=0;
689-
690+
691 virtual int savepoint_set(ulong sp)=0;
692 virtual ulong savepoint_release(ulong sp)=0;
693 virtual ulong savepoint_rollback(ulong sp)=0;
694 virtual void savepoint_restrict(ulong sp)=0;
695-
696+
697 virtual ulong last_savepoint() const=0;
698 virtual ulong actual_savepoint() const=0;
699 virtual bool is_autocommit() const=0;
700
701 virtual bool table_metadata(ha_statistics *stats, const char *table_name,
702 uint table_name_length, uint flag) = 0;
703-
704+
705 /* resultset operations */
706-
707+
708 virtual void free_result(FEDERATEDX_IO_RESULT *io_result)=0;
709 virtual unsigned int get_num_fields(FEDERATEDX_IO_RESULT *io_result)=0;
710 virtual my_ulonglong get_num_rows(FEDERATEDX_IO_RESULT *io_result)=0;
711@@ -206,6 +206,13 @@
712 unsigned int column)=0;
713 virtual bool is_column_null(const FEDERATEDX_IO_ROW *row,
714 unsigned int column) const=0;
715+
716+ virtual size_t get_ref_length() const=0;
717+ virtual void mark_position(FEDERATEDX_IO_RESULT *io_result,
718+ void *ref)=0;
719+ virtual int seek_position(FEDERATEDX_IO_RESULT **io_result,
720+ const void *ref)=0;
721+
722 };
723
724
725@@ -215,12 +222,12 @@
726 ulong savepoint_level;
727 ulong savepoint_stmt;
728 ulong savepoint_next;
729-
730+
731 void release_scan();
732 public:
733 federatedx_txn();
734 ~federatedx_txn();
735-
736+
737 bool has_connections() const { return txn_list != NULL; }
738 bool in_transaction() const { return savepoint_next != 0; }
739 int acquire(FEDERATEDX_SHARE *share, bool readonly, federatedx_io **io);
740@@ -254,8 +261,12 @@
741 federatedx_txn *txn;
742 federatedx_io *io;
743 FEDERATEDX_IO_RESULT *stored_result;
744+ /**
745+ Array of all stored results we get during a query execution.
746+ */
747+ DYNAMIC_ARRAY results;
748+ bool position_called;
749 uint fetch_num; // stores the fetch num
750- FEDERATEDX_IO_OFFSET current_position; // Current position used by ::position()
751 int remote_error_number;
752 char remote_error_buf[FEDERATEDX_QUERY_BUFFER_SIZE];
753 bool ignore_duplicates, replace_duplicates;
754@@ -269,7 +280,7 @@
755 */
756 uint convert_row_to_internal_format(uchar *buf, FEDERATEDX_IO_ROW *row,
757 FEDERATEDX_IO_RESULT *result);
758- bool create_where_from_key(String *to, KEY *key_info,
759+ bool create_where_from_key(String *to, KEY *key_info,
760 const key_range *start_key,
761 const key_range *end_key,
762 bool records_in_range, bool eq_range);
763@@ -348,18 +359,18 @@
764 Talk to Kostja about this - how to get the
765 number of rows * ...
766 disk scan time on other side (block size, size of the row) + network time ...
767- The reason for "records * 1000" is that such a large number forces
768+ The reason for "records * 1000" is that such a large number forces
769 this to use indexes "
770 */
771 double scan_time()
772 {
773 DBUG_PRINT("info", ("records %lu", (ulong) stats.records));
774- return (double)(stats.records*1000);
775+ return (double)(stats.records*1000);
776 }
777 /*
778 The next method will never be called if you do not implement indexes.
779 */
780- double read_time(uint index, uint ranges, ha_rows rows)
781+ double read_time(uint index, uint ranges, ha_rows rows)
782 {
783 /*
784 Per Brian, this number is bugus, but this method must be implemented,

Subscribers

People subscribed via source and target branches