Commit c43058d0 authored by Andrew McDonnell's avatar Andrew McDonnell

Fix for order by crash, release dangling cursor when unlocking table.

parent 174fc2a8
DROP TABLE IF EXISTS graph_base;
DROP TABLE IF EXISTS graph;
CREATE TABLE graph_base (
from_id INT UNSIGNED NOT NULL,
to_id INT UNSIGNED NOT NULL,
another_id INT UNSIGNED NOT NULL DEFAULT 1,
w DOUBLE NOT NULL DEFAULT 1,
PRIMARY KEY (from_id,to_id),
INDEX (to_id)
) ENGINE=MyISAM;
CREATE TABLE graph (
latch VARCHAR(32) NULL,
origid BIGINT UNSIGNED NULL,
destid BIGINT UNSIGNED NULL,
weight DOUBLE NULL,
seq BIGINT UNSIGNED NULL,
linkid BIGINT UNSIGNED NULL,
KEY (latch, origid, destid) USING HASH,
KEY (latch, destid, origid) USING HASH
) ENGINE=OQGRAPH DATA_TABLE='graph_base' ORIGID='from_id', DESTID='to_id', WEIGHT='w';
INSERT INTO graph_base(from_id, to_id) VALUES (1,2), (2,1);
INSERT INTO graph_base(from_id, to_id) VALUES (1,3), (3,1);
INSERT INTO graph_base(from_id, to_id) VALUES (1,4), (4,1);
INSERT INTO graph_base(from_id, to_id) VALUES (3,4), (4,3);
SELECT * from graph;
latch origid destid weight seq linkid
NULL 1 2 1 NULL NULL
NULL 2 1 1 NULL NULL
NULL 1 3 1 NULL NULL
NULL 3 1 1 NULL NULL
NULL 1 4 1 NULL NULL
NULL 4 1 1 NULL NULL
NULL 3 4 1 NULL NULL
NULL 4 3 1 NULL NULL
SELECT * FROM graph WHERE latch='1' and destid=2 and origid=1;
latch origid destid weight seq linkid
1 1 2 NULL 0 1
1 1 2 1 1 2
SELECT * FROM graph WHERE latch='1' and destid=2 and origid=1 order by seq;
latch origid destid weight seq linkid
1 1 2 NULL 0 1
1 1 2 1 1 2
DROP TABLE graph;
DROP TABLE graph_base;
...@@ -34,8 +34,8 @@ INSERT INTO graph_base(from_id, to_id) VALUES (1,3), (3,1); ...@@ -34,8 +34,8 @@ INSERT INTO graph_base(from_id, to_id) VALUES (1,3), (3,1);
INSERT INTO graph_base(from_id, to_id) VALUES (1,4), (4,1); INSERT INTO graph_base(from_id, to_id) VALUES (1,4), (4,1);
INSERT INTO graph_base(from_id, to_id) VALUES (3,4), (4,3); INSERT INTO graph_base(from_id, to_id) VALUES (3,4), (4,3);
#SELECT * from graph; SELECT * from graph;
#SELECT * FROM graph WHERE latch='1' and destid=2 and origid=1; SELECT * FROM graph WHERE latch='1' and destid=2 and origid=1;
SELECT * FROM graph WHERE latch='1' and destid=2 and origid=1 order by seq; SELECT * FROM graph WHERE latch='1' and destid=2 and origid=1 order by seq;
DROP TABLE graph; DROP TABLE graph;
......
...@@ -147,6 +147,17 @@ namespace open_query ...@@ -147,6 +147,17 @@ namespace open_query
HAVE_EDGE = 4, HAVE_EDGE = 4,
}; };
// Force assignment operator, so we can trace through in the debugger
inline reference& operator=(const reference& ref)
{
m_flags = ref.m_flags;
m_sequence = ref.m_sequence;
m_vertex = ref.m_vertex;
m_edge = ref.m_edge;
m_weight = ref.m_weight;
return *this;
}
inline reference() inline reference()
: m_flags(0), m_sequence(0), : m_flags(0), m_sequence(0),
m_vertex(graph_traits<Graph>::null_vertex()), m_vertex(graph_traits<Graph>::null_vertex()),
...@@ -162,7 +173,8 @@ namespace open_query ...@@ -162,7 +173,8 @@ namespace open_query
inline reference(int s, Vertex v, const optional<Edge> &e, inline reference(int s, Vertex v, const optional<Edge> &e,
const optional<EdgeWeight> &w) const optional<EdgeWeight> &w)
: m_flags(HAVE_SEQUENCE | (w ? HAVE_WEIGHT : 0) | (e ? HAVE_EDGE : 0)), : m_flags(HAVE_SEQUENCE | (w ? HAVE_WEIGHT : 0) | (e ? HAVE_EDGE : 0)),
m_sequence(s), m_vertex(v) m_sequence(s), m_vertex(v),
m_edge(), m_weight(0)
{ {
if (w) m_weight= *w; if (w) m_weight= *w;
if (e) m_edge= *e; if (e) m_edge= *e;
...@@ -685,6 +697,15 @@ namespace open_query ...@@ -685,6 +697,15 @@ namespace open_query
if (retainedLatch) { lastRetainedLatch = strdup(retainedLatch); } if (retainedLatch) { lastRetainedLatch = strdup(retainedLatch); }
} }
// Because otherwise things can happen and we havent freed a resource since the end of the last query...
void oqgraph::release_cursor() throw() {
if (share->g._cursor) {
delete share->g._cursor;
}
delete cursor; cursor= 0;
row_info= empty_row;
}
int oqgraph::search(int *latch, VertexID *orig_id, VertexID *dest_id) throw() int oqgraph::search(int *latch, VertexID *orig_id, VertexID *dest_id) throw()
{ {
...@@ -947,7 +968,15 @@ namespace open_query ...@@ -947,7 +968,15 @@ namespace open_query
if (cursor) if (cursor)
cursor->current(ref); cursor->current(ref);
else else
ref = reference(); // avoid assignment operator because the intrusive_ptr swaps for unknown reasons, which means if ref is uninitialised it segfaults // Beware: internally this eventually causes a swap by intrusive_ptr, so ref must be initialised to sane on all cases
ref = reference();
}
void oqgraph::init_row_ref(void *ref_ptr) throw()
{
// Placement new will cause a constructor to be called avoiding the assignment operator of intrusive_ptr
// This doesnt allocate any memory, assumes ref_ptr is the correct size(!)
new (ref_ptr) reference();
} }
int oqgraph::random(bool scan) throw() int oqgraph::random(bool scan) throw()
......
...@@ -121,6 +121,7 @@ namespace open_query ...@@ -121,6 +121,7 @@ namespace open_query
int fetch_row(row&) throw(); int fetch_row(row&) throw();
int fetch_row(row&, const void*) throw(); int fetch_row(row&, const void*) throw();
void row_ref(void*) throw(); void row_ref(void*) throw();
void init_row_ref(void*) throw();
static oqgraph* create(oqgraph_share*) throw(); static oqgraph* create(oqgraph_share*) throw();
static oqgraph_share *create(TABLE*,Field*,Field*,Field*) throw(); static oqgraph_share *create(TABLE*,Field*,Field*,Field*) throw();
...@@ -128,6 +129,8 @@ namespace open_query ...@@ -128,6 +129,8 @@ namespace open_query
static void free(oqgraph*) throw(); static void free(oqgraph*) throw();
static void free(oqgraph_share*) throw(); static void free(oqgraph_share*) throw();
void release_cursor() throw();
static const size_t sizeof_ref; static const size_t sizeof_ref;
private: private:
char *lastRetainedLatch; char *lastRetainedLatch;
......
...@@ -795,7 +795,8 @@ int ha_oqgraph::index_read(byte * buf, const byte * key, uint key_len, ...@@ -795,7 +795,8 @@ int ha_oqgraph::index_read(byte * buf, const byte * key, uint key_len,
enum ha_rkey_function find_flag) enum ha_rkey_function find_flag)
{ {
DBUG_ASSERT(inited==INDEX); DBUG_ASSERT(inited==INDEX);
graph->row_ref((void*) ref); // reset before we have a cursor, so the memory is inited, avoiding the sefgault in position() when select with order by (bug #1133093) // reset before we have a cursor, so the memory is not junk, avoiding the sefgault in position() when select with order by (bug #1133093)
graph->init_row_ref(ref);
return index_read_idx(buf, active_index, key, key_len, find_flag); return index_read_idx(buf, active_index, key, key_len, find_flag);
} }
...@@ -1107,6 +1108,15 @@ int ha_oqgraph::delete_all_rows() ...@@ -1107,6 +1108,15 @@ int ha_oqgraph::delete_all_rows()
int ha_oqgraph::external_lock(THD *thd, int lock_type) int ha_oqgraph::external_lock(THD *thd, int lock_type)
{ {
// This method is also called to _unlock_ (lock_type == F_UNLCK)
// Which means we need to release things before we let the underlying backing table lock go...
if (lock_type == F_UNLCK) {
// If we have an index open on the backing table, we need to close it out here
// this means destroying any open cursor first.
// Then we can let the unlock go through to the backing table
graph->release_cursor();
}
return edges->file->ha_external_lock(thd, lock_type); return edges->file->ha_external_lock(thd, lock_type);
} }
......
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