Merge lp:~gl-az/percona-server/ST-31919-5.6 into lp:percona-server/5.6

Proposed by George Ormond Lorch III
Status: Superseded
Proposed branch: lp:~gl-az/percona-server/ST-31919-5.6
Merge into: lp:percona-server/5.6
Diff against target: 470 lines (+231/-50)
4 files modified
Percona-Server/mysql-test/suite/federated/federated_bug_68354.result (+80/-0)
Percona-Server/mysql-test/suite/federated/federated_bug_68354.test (+79/-0)
Percona-Server/storage/federated/ha_federated.cc (+56/-43)
Percona-Server/storage/federated/ha_federated.h (+16/-7)
To merge this branch: bzr merge lp:~gl-az/percona-server/ST-31919-5.6
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Needs Fixing
Review via email: mp+169956@code.launchpad.net

This proposal has been superseded by a proposal from 2013-06-18.

Description of the change

Fix for upstream 68354 and lp 1182572:
  Server crashes on update/join FEDERATED + local table when only 1 local row

This issue seems to be the result of a poor or changed assumption in the order
in which handler calls are made. In this specific scenario (a join with a local
table that has exactly one matching record) there is an assumption in the code
that a call to position will always come after a 'rnd_init/index_init' and
'rnd_next/index_read' but before 'rnd_end/index_end' is called.

The failing call order is:
  ha_federated::index_init
  ha_federated::index_read
  ha_federated::index_end
  ha_federated::position
  ha_federated::rnd_init
  ha_federated::extra
  ha_federated::rnd_pos

So here you can see position is getting called _outside_ of the scope of an
_init.._end table and/or index scan. This does indicate a change/problem in
the server but that is outside the scope of this fix.

As results are fetched, they are added to an interal list of result sets called
'results'. The last result set/current position is also held in the
'stored_result' value. If 'index_end' or 'rnd_end' is called before 'position'
has been called, the 'stored_result' is zeroed out and that result is removed
from the 'stored_results' list. When 'position' is called, a NULL result is
returned, which is then passed back through 'rnd_pos', which then dereferences
the NULL value and tries to manipulate some of the result internals, crashing.

So seems that the intention of the whole 'stored_result' was to have a place
to track all results allocated for the purposes of keeping them valid for the
'position' and 'rnd_pos' calls.

My approch to fixing this is to restructure this somewhan and instead of
tracking all results allocated in the 'results' list and popping them out when
they are discovered to not be needed, I went the other way. The results only
get addes to a storage list when it has been proven that they are in fact
needed later. So now for each new result set, it is temporarily stored in a
new value called 'last_result'. Whenever a new last_result needs created, it is
set by calling a new function 'set_last_result'. This function will check to
see if 'position' has been called on that result and if so, add it to the
(renamed) list 'stored_results' and clears the 'position_called' flag, else it
will free the 'last_result'. It then sets the new 'last_result' value.

Because of the out of scan scope call of position, we can no longer clear the
'stored_results' lists on '_end'. It will be cleared now when 'reset' is
called.

I have created a test case (suite/federated/federated_bug_68354.test) and
verified that it fails without the fix. Everything tests out under the federated
suite and the issue appears fixed.

The only downside is that a lengthy query could use a lot of memory while
hanging onto old 'position'ed results but I can't see how that can be safely
avoided in this particular handler.

To post a comment you must log in.
Revision history for this message
George Ormond Lorch III (gl-az) wrote :
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Same comments as in the 5.5 MP.

review: Needs Fixing

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'Percona-Server/mysql-test/suite/federated/federated_bug_68354.result'
--- Percona-Server/mysql-test/suite/federated/federated_bug_68354.result 1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/federated/federated_bug_68354.result 2013-06-18 18:42:38 +0000
@@ -0,0 +1,80 @@
1CREATE DATABASE federated;
2CREATE DATABASE federated;
3SET @OLD_MASTER_CONCURRENT_INSERT= @@GLOBAL.CONCURRENT_INSERT;
4SET @@GLOBAL.CONCURRENT_INSERT= 0;
5SET @OLD_SLAVE_CONCURRENT_INSERT= @@GLOBAL.CONCURRENT_INSERT;
6SET @@GLOBAL.CONCURRENT_INSERT= 0;
7DROP TABLE IF EXISTS federated.t1;
8Warnings:
9Note 1051 Unknown table 'federated.t1'
10CREATE TABLE federated.t1 (
11`id` int(20) NOT NULL,
12`dummy` int(20) DEFAULT NULL,
13PRIMARY KEY (`id`))
14ENGINE="MyISAM"
15 DEFAULT CHARSET=latin1;
16INSERT INTO federated.t1 (`id`) VALUES
17(1001), (1002), (1003), (1004), (1005),
18(1006), (1007), (1008), (1009), (1010);
19CREATE TABLE federated.t1 (
20`id` int(20) NOT NULL,
21`dummy` int(20) DEFAULT NULL,
22PRIMARY KEY (`id`))
23ENGINE="FEDERATED"
24 DEFAULT CHARSET=latin1
25CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
26CREATE TABLE federated.t2 (
27`id` int(20) NOT NULL,
28`dummy` int(20) NOT NULL,
29PRIMARY KEY (`id`))
30ENGINE="MyISAM"
31 DEFAULT CHARSET=latin1;
32INSERT INTO federated.t2 (`id`, `dummy`) VALUES (1005, 5);
33SELECT * FROM federated.t1;
34id dummy
351001 NULL
361002 NULL
371003 NULL
381004 NULL
391005 NULL
401006 NULL
411007 NULL
421008 NULL
431009 NULL
441010 NULL
45UPDATE federated.t1 ft1 INNER JOIN federated.t2 ft2 ON ft1.id = ft2.id SET ft1.dummy = ft2.dummy WHERE ft1.dummy IS NULL;
46SELECT * FROM federated.t1;
47id dummy
481001 NULL
491002 NULL
501003 NULL
511004 NULL
521005 5
531006 NULL
541007 NULL
551008 NULL
561009 NULL
571010 NULL
58DELETE FROM federated.t1 WHERE id = 1005;
59SELECT * FROM federated.t1 WHERE id = 1005;
60id dummy
61SELECT * FROM federated.t1;
62id dummy
631001 NULL
641002 NULL
651003 NULL
661004 NULL
671006 NULL
681007 NULL
691008 NULL
701009 NULL
711010 NULL
72DROP TABLE federated.t2;
73DROP TABLE federated.t1;
74DROP TABLE federated.t1;
75SET @@GLOBAL.CONCURRENT_INSERT= @OLD_MASTER_CONCURRENT_INSERT;
76SET @@GLOBAL.CONCURRENT_INSERT= @OLD_SLAVE_CONCURRENT_INSERT;
77DROP TABLE IF EXISTS federated.t1;
78DROP DATABASE federated;
79DROP TABLE IF EXISTS federated.t1;
80DROP DATABASE federated;
081
=== added file 'Percona-Server/mysql-test/suite/federated/federated_bug_68354.test'
--- Percona-Server/mysql-test/suite/federated/federated_bug_68354.test 1970-01-01 00:00:00 +0000
+++ Percona-Server/mysql-test/suite/federated/federated_bug_68354.test 2013-06-18 18:42:38 +0000
@@ -0,0 +1,79 @@
1# Bug 1182572 68354: Server crashes on update/join FEDERATED + local table when
2# only 1 local row.
3#
4# When updating a federated table with UPDATE ... JOIN, the server consistently
5# crashes with Signal 11 when only 1 row exists in the local table involved in
6# the join and that 1 row can be joined with a row in the federated table.
7#
8
9--source suite/federated/include/federated.inc
10
11connection default;
12
13# Disable concurrent inserts to avoid test failures when reading
14# data from concurrent connections (insert might return before
15# the data is actually in the table).
16SET @OLD_MASTER_CONCURRENT_INSERT= @@GLOBAL.CONCURRENT_INSERT;
17SET @@GLOBAL.CONCURRENT_INSERT= 0;
18
19connection slave;
20SET @OLD_SLAVE_CONCURRENT_INSERT= @@GLOBAL.CONCURRENT_INSERT;
21SET @@GLOBAL.CONCURRENT_INSERT= 0;
22DROP TABLE IF EXISTS federated.t1;
23CREATE TABLE federated.t1 (
24 `id` int(20) NOT NULL,
25 `dummy` int(20) DEFAULT NULL,
26 PRIMARY KEY (`id`))
27 ENGINE="MyISAM"
28 DEFAULT CHARSET=latin1;
29
30INSERT INTO federated.t1 (`id`) VALUES
31 (1001), (1002), (1003), (1004), (1005),
32 (1006), (1007), (1008), (1009), (1010);
33
34connection master;
35--replace_result $SLAVE_MYPORT SLAVE_PORT
36eval CREATE TABLE federated.t1 (
37 `id` int(20) NOT NULL,
38 `dummy` int(20) DEFAULT NULL,
39 PRIMARY KEY (`id`))
40 ENGINE="FEDERATED"
41 DEFAULT CHARSET=latin1
42 CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
43
44CREATE TABLE federated.t2 (
45 `id` int(20) NOT NULL,
46 `dummy` int(20) NOT NULL,
47 PRIMARY KEY (`id`))
48 ENGINE="MyISAM"
49 DEFAULT CHARSET=latin1;
50
51INSERT INTO federated.t2 (`id`, `dummy`) VALUES (1005, 5);
52
53SELECT * FROM federated.t1;
54
55# master would crash here before bug fix
56UPDATE federated.t1 ft1 INNER JOIN federated.t2 ft2 ON ft1.id = ft2.id SET ft1.dummy = ft2.dummy WHERE ft1.dummy IS NULL;
57
58# sanity test to make sure correct rows are being returned and server doesn't
59# also crash during DELETE
60SELECT * FROM federated.t1;
61DELETE FROM federated.t1 WHERE id = 1005;
62SELECT * FROM federated.t1 WHERE id = 1005;
63
64SELECT * FROM federated.t1;
65
66DROP TABLE federated.t2;
67DROP TABLE federated.t1;
68
69connection slave;
70DROP TABLE federated.t1;
71
72connection default;
73
74SET @@GLOBAL.CONCURRENT_INSERT= @OLD_MASTER_CONCURRENT_INSERT;
75connection slave;
76SET @@GLOBAL.CONCURRENT_INSERT= @OLD_SLAVE_CONCURRENT_INSERT;
77
78connection default;
79--source suite/federated/include/federated_cleanup.inc
080
=== modified file 'Percona-Server/storage/federated/ha_federated.cc'
--- Percona-Server/storage/federated/ha_federated.cc 2013-05-12 06:24:46 +0000
+++ Percona-Server/storage/federated/ha_federated.cc 2013-06-18 18:42:38 +0000
@@ -1,4 +1,4 @@
1/* Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.1/* Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
22
3 This program is free software; you can redistribute it and/or modify3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by4 it under the terms of the GNU General Public License as published by
@@ -900,7 +900,7 @@
900ha_federated::ha_federated(handlerton *hton,900ha_federated::ha_federated(handlerton *hton,
901 TABLE_SHARE *table_arg)901 TABLE_SHARE *table_arg)
902 :handler(hton, table_arg),902 :handler(hton, table_arg),
903 mysql(0), stored_result(0)903 mysql(0), last_result(0), position_called(false)
904{904{
905 trx_next= 0;905 trx_next= 0;
906 memset(&bulk_insert, 0, sizeof(bulk_insert));906 memset(&bulk_insert, 0, sizeof(bulk_insert));
@@ -1653,7 +1653,7 @@
1653 ref_length= sizeof(MYSQL_RES *) + sizeof(MYSQL_ROW_OFFSET);1653 ref_length= sizeof(MYSQL_RES *) + sizeof(MYSQL_ROW_OFFSET);
1654 DBUG_PRINT("info", ("ref_length: %u", ref_length));1654 DBUG_PRINT("info", ("ref_length: %u", ref_length));
16551655
1656 my_init_dynamic_array(&results, sizeof(MYSQL_RES *), 4, 4);1656 my_init_dynamic_array(&stored_results, sizeof(MYSQL_RES *), 4, 4);
1657 reset();1657 reset();
16581658
1659 DBUG_RETURN(0);1659 DBUG_RETURN(0);
@@ -1677,9 +1677,7 @@
16771677
1678 DBUG_ENTER("ha_federated::close");1678 DBUG_ENTER("ha_federated::close");
16791679
1680 free_result();1680 delete_dynamic(&stored_results);
1681
1682 delete_dynamic(&results);
1683 1681
1684 /* Disconnect from mysql */1682 /* Disconnect from mysql */
1685 mysql_close(mysql);1683 mysql_close(mysql);
@@ -2326,13 +2324,18 @@
2326 uint key_len, ha_rkey_function find_flag)2324 uint key_len, ha_rkey_function find_flag)
2327{2325{
2328 int rc;2326 int rc;
2327 MYSQL_RES* mysql_result;
2328
2329 DBUG_ENTER("ha_federated::index_read");2329 DBUG_ENTER("ha_federated::index_read");
23302330
2331 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);2331 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
2332 free_result();
2333 rc= index_read_idx_with_result_set(buf, active_index, key,2332 rc= index_read_idx_with_result_set(buf, active_index, key,
2334 key_len, find_flag,2333 key_len, find_flag,
2335 &stored_result);2334 &mysql_result);
2335
2336 if (rc == 0)
2337 set_last_result(mysql_result);
2338
2336 MYSQL_INDEX_READ_ROW_DONE(rc);2339 MYSQL_INDEX_READ_ROW_DONE(rc);
2337 DBUG_RETURN(rc);2340 DBUG_RETURN(rc);
2338}2341}
@@ -2363,7 +2366,6 @@
2363 &mysql_result)))2366 &mysql_result)))
2364 DBUG_RETURN(retval);2367 DBUG_RETURN(retval);
2365 mysql_free_result(mysql_result);2368 mysql_free_result(mysql_result);
2366 results.elements--;
2367 DBUG_RETURN(0);2369 DBUG_RETURN(0);
2368}2370}
23692371
@@ -2428,7 +2430,6 @@
2428 if ((retval= read_next(buf, *result)))2430 if ((retval= read_next(buf, *result)))
2429 {2431 {
2430 mysql_free_result(*result);2432 mysql_free_result(*result);
2431 results.elements--;
2432 *result= 0;2433 *result= 0;
2433 table->status= STATUS_NOT_FOUND;2434 table->status= STATUS_NOT_FOUND;
2434 DBUG_RETURN(retval);2435 DBUG_RETURN(retval);
@@ -2480,6 +2481,7 @@
2480 bool eq_range_arg, bool sorted)2481 bool eq_range_arg, bool sorted)
2481{2482{
2482 char sql_query_buffer[FEDERATED_QUERY_BUFFER_SIZE];2483 char sql_query_buffer[FEDERATED_QUERY_BUFFER_SIZE];
2484 MYSQL_RES *mysql_result;
2483 int retval;2485 int retval;
2484 String sql_query(sql_query_buffer,2486 String sql_query(sql_query_buffer,
2485 sizeof(sql_query_buffer),2487 sizeof(sql_query_buffer),
@@ -2501,13 +2503,15 @@
2501 }2503 }
2502 sql_query.length(0);2504 sql_query.length(0);
25032505
2504 if (!(stored_result= store_result(mysql)))2506 if (!(mysql_result= store_result(mysql)))
2505 {2507 {
2506 retval= HA_ERR_END_OF_FILE;2508 retval= HA_ERR_END_OF_FILE;
2507 goto error;2509 goto error;
2508 }2510 }
25092511
2510 retval= read_next(table->record[0], stored_result);2512 set_last_result(mysql_result);
2513
2514 retval= read_next(table->record[0], mysql_result);
2511 MYSQL_INDEX_READ_ROW_DONE(retval);2515 MYSQL_INDEX_READ_ROW_DONE(retval);
2512 DBUG_RETURN(retval);2516 DBUG_RETURN(retval);
25132517
@@ -2536,7 +2540,7 @@
2536 DBUG_ENTER("ha_federated::index_next");2540 DBUG_ENTER("ha_federated::index_next");
2537 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);2541 MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
2538 ha_statistic_increment(&SSV::ha_read_next_count);2542 ha_statistic_increment(&SSV::ha_read_next_count);
2539 retval= read_next(buf, stored_result);2543 retval= read_next(buf, get_last_result());
2540 MYSQL_INDEX_READ_ROW_DONE(retval);2544 MYSQL_INDEX_READ_ROW_DONE(retval);
2541 DBUG_RETURN(retval);2545 DBUG_RETURN(retval);
2542}2546}
@@ -2557,6 +2561,7 @@
25572561
2558int ha_federated::rnd_init(bool scan)2562int ha_federated::rnd_init(bool scan)
2559{2563{
2564 MYSQL_RES *mysql_result;
2560 DBUG_ENTER("ha_federated::rnd_init");2565 DBUG_ENTER("ha_federated::rnd_init");
2561 /*2566 /*
2562 The use of the 'scan' flag is incredibly important for this handler2567 The use of the 'scan' flag is incredibly important for this handler
@@ -2596,8 +2601,9 @@
2596 if (scan)2601 if (scan)
2597 {2602 {
2598 if (real_query(share->select_query, strlen(share->select_query)) ||2603 if (real_query(share->select_query, strlen(share->select_query)) ||
2599 !(stored_result= store_result(mysql)))2604 !(mysql_result= store_result(mysql)))
2600 DBUG_RETURN(stash_remote_error());2605 DBUG_RETURN(stash_remote_error());
2606 set_last_result(mysql_result);
2601 }2607 }
2602 DBUG_RETURN(0);2608 DBUG_RETURN(0);
2603}2609}
@@ -2606,14 +2612,14 @@
2606int ha_federated::rnd_end()2612int ha_federated::rnd_end()
2607{2613{
2608 DBUG_ENTER("ha_federated::rnd_end");2614 DBUG_ENTER("ha_federated::rnd_end");
2609 DBUG_RETURN(index_end());2615 active_index= MAX_KEY;
2616 DBUG_RETURN(0);
2610}2617}
26112618
26122619
2613int ha_federated::index_end(void)2620int ha_federated::index_end(void)
2614{2621{
2615 DBUG_ENTER("ha_federated::index_end");2622 DBUG_ENTER("ha_federated::index_end");
2616 free_result();
2617 active_index= MAX_KEY;2623 active_index= MAX_KEY;
2618 DBUG_RETURN(0);2624 DBUG_RETURN(0);
2619}2625}
@@ -2644,7 +2650,7 @@
2644{2650{
2645 DBUG_ENTER("ha_federated::rnd_next_int");2651 DBUG_ENTER("ha_federated::rnd_next_int");
26462652
2647 if (stored_result == 0)2653 if (get_last_result() == 0)
2648 {2654 {
2649 /*2655 /*
2650 Return value of rnd_init is not always checked (see records.cc),2656 Return value of rnd_init is not always checked (see records.cc),
@@ -2653,7 +2659,7 @@
2653 */2659 */
2654 DBUG_RETURN(1);2660 DBUG_RETURN(1);
2655 }2661 }
2656 DBUG_RETURN(read_next(buf, stored_result));2662 DBUG_RETURN(read_next(buf, get_last_result()));
2657}2663}
26582664
26592665
@@ -2721,16 +2727,20 @@
27212727
2722void ha_federated::position(const uchar *record __attribute__ ((unused)))2728void ha_federated::position(const uchar *record __attribute__ ((unused)))
2723{2729{
2730 MYSQL_RES* mysql_result;
2724 DBUG_ENTER("ha_federated::position");2731 DBUG_ENTER("ha_federated::position");
2725 2732
2726 DBUG_ASSERT(stored_result);2733 mysql_result= get_last_result();
27272734
2728 position_called= TRUE;2735 DBUG_ASSERT(mysql_result);
2736
2729 /* Store result set address. */2737 /* Store result set address. */
2730 memcpy(ref, &stored_result, sizeof(MYSQL_RES *));2738 memcpy(ref, &mysql_result, sizeof(MYSQL_RES *));
2731 /* Store data cursor position. */2739 /* Store data cursor position. */
2732 memcpy(ref + sizeof(MYSQL_RES *), &current_position,2740 memcpy(ref + sizeof(MYSQL_RES *), &current_position,
2733 sizeof(MYSQL_ROW_OFFSET));2741 sizeof(MYSQL_ROW_OFFSET));
2742
2743 position_called= true;
2734 DBUG_VOID_RETURN;2744 DBUG_VOID_RETURN;
2735}2745}
27362746
@@ -2966,14 +2976,20 @@
2966 replace_duplicates= FALSE;2976 replace_duplicates= FALSE;
29672977
2968 /* Free stored result sets. */2978 /* Free stored result sets. */
2969 for (uint i= 0; i < results.elements; i++)2979 for (uint i= 0; i < stored_results.elements; i++)
2970 {2980 {
2971 MYSQL_RES *result;2981 MYSQL_RES *result;
2972 get_dynamic(&results, (uchar *) &result, i);2982 get_dynamic(&stored_results, (uchar *) &result, i);
2973 mysql_free_result(result);2983 mysql_free_result(result);
2974 }2984 }
2975 reset_dynamic(&results);2985 reset_dynamic(&stored_results);
29762986
2987 if (last_result)
2988 {
2989 mysql_free_result(last_result);
2990 last_result= 0;
2991 }
2992 position_called= false;
2977 return 0;2993 return 0;
2978}2994}
29792995
@@ -3261,31 +3277,28 @@
32613277
3262MYSQL_RES *ha_federated::store_result(MYSQL *mysql_arg)3278MYSQL_RES *ha_federated::store_result(MYSQL *mysql_arg)
3263{3279{
3264 MYSQL_RES *result= mysql_store_result(mysql_arg);
3265 DBUG_ENTER("ha_federated::store_result");3280 DBUG_ENTER("ha_federated::store_result");
3266 if (result)3281 DBUG_RETURN(mysql_store_result(mysql_arg));
3267 {
3268 (void) insert_dynamic(&results, &result);
3269 }
3270 position_called= FALSE;
3271 DBUG_RETURN(result);
3272}3282}
32733283
32743284
3275void ha_federated::free_result()3285void ha_federated::set_last_result(MYSQL_RES *result)
3276{3286{
3277 DBUG_ENTER("ha_federated::free_result");3287 DBUG_ENTER("ha_federated::set_last_result");
3278 if (stored_result && !position_called)3288 if (position_called)
3279 {3289 {
3280 mysql_free_result(stored_result);3290 insert_dynamic(&stored_results, (uchar*) &last_result);
3281 stored_result= 0;3291 position_called= false;
3282 if (results.elements > 0)3292 }
3283 results.elements--;3293 else
3284 }3294 {
3295 mysql_free_result(last_result);
3296 }
3297 last_result= result;
3285 DBUG_VOID_RETURN;3298 DBUG_VOID_RETURN;
3286}3299}
32873300
3288 3301
3289int ha_federated::external_lock(THD *thd, int lock_type)3302int ha_federated::external_lock(THD *thd, int lock_type)
3290{3303{
3291 int error= 0;3304 int error= 0;
32923305
=== modified file 'Percona-Server/storage/federated/ha_federated.h'
--- Percona-Server/storage/federated/ha_federated.h 2012-08-22 01:40:20 +0000
+++ Percona-Server/storage/federated/ha_federated.h 2013-06-18 18:42:38 +0000
@@ -79,11 +79,19 @@
79 THR_LOCK_DATA lock; /* MySQL lock */79 THR_LOCK_DATA lock; /* MySQL lock */
80 FEDERATED_SHARE *share; /* Shared lock info */80 FEDERATED_SHARE *share; /* Shared lock info */
81 MYSQL *mysql; /* MySQL connection */81 MYSQL *mysql; /* MySQL connection */
82 MYSQL_RES *stored_result;82 /*
83 /**83 Last fetched result, freed if !position_called when set to next result.
84 Array of all stored results we get during a query execution.84 */
85 */85 MYSQL_RES *last_result;
86 DYNAMIC_ARRAY results;86 /*
87 Array of stored results that exist because of position call.
88 */
89 DYNAMIC_ARRAY stored_results;
90 /*
91 Indicates if position has been called since last_result was set, used to
92 determine if last_result needs pushed into stored_results when
93 set_last_result is called.
94 */
87 bool position_called;95 bool position_called;
88 uint fetch_num; // stores the fetch num96 uint fetch_num; // stores the fetch num
89 MYSQL_ROW_OFFSET current_position; // Current position used by ::position()97 MYSQL_ROW_OFFSET current_position; // Current position used by ::position()
@@ -258,8 +266,9 @@
258 bool get_error_message(int error, String *buf);266 bool get_error_message(int error, String *buf);
259 267
260 MYSQL_RES *store_result(MYSQL *mysql);268 MYSQL_RES *store_result(MYSQL *mysql);
261 void free_result();269 void set_last_result(MYSQL_RES *result);
262 270 MYSQL_RES *get_last_result() const{ return last_result; }
271
263 int external_lock(THD *thd, int lock_type);272 int external_lock(THD *thd, int lock_type);
264 int connection_commit();273 int connection_commit();
265 int connection_rollback();274 int connection_rollback();

Subscribers

People subscribed via source and target branches