diff --git a/mysql-test/suite/oqgraph/regression_796647c.result b/mysql-test/suite/oqgraph/regression_796647c.result new file mode 100644 index 00000000000..d648e7ff192 --- /dev/null +++ b/mysql-test/suite/oqgraph/regression_796647c.result @@ -0,0 +1,127 @@ +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, +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'; +INSERT INTO graph_base(from_id, to_id) VALUES (1,2), (2,1); +SELECT count(*) FROM graph; +count(*) +2 +SELECT count(*) FROM graph_base; +count(*) +2 +INSERT INTO graph_base(from_id, to_id) VALUES (12,10); +SELECT count(*) FROM graph; +count(*) +3 +SELECT count(*) FROM graph_base; +count(*) +3 +INSERT INTO graph_base(from_id, to_id) VALUES (14,13); +SELECT count(*) FROM graph; +count(*) +4 +SELECT count(*) FROM graph_base; +count(*) +4 +DELETE FROM graph_base where from_id=10 and to_id=11; +INSERT INTO graph_base(from_id, to_id) VALUES (10,15); +INSERT INTO graph_base(from_id, to_id) VALUES (15,13); +INSERT INTO graph_base(from_id, to_id) VALUES (10,11); +SELECT count(*) FROM graph; +count(*) +7 +SELECT count(*) FROM graph_base; +count(*) +7 +INSERT INTO graph_base(from_id, to_id) VALUES (21,22); +INSERT INTO graph_base (from_id,to_id) VALUES (4,6); +SELECT count(*) FROM graph; +count(*) +9 +SELECT count(*) FROM graph_base; +count(*) +9 +SELECT * FROM graph where latch='0'; +latch origid destid weight seq linkid +0 NULL NULL NULL NULL 1 +0 NULL NULL NULL NULL 2 +0 NULL NULL NULL NULL 12 +0 NULL NULL NULL NULL 10 +0 NULL NULL NULL NULL 14 +0 NULL NULL NULL NULL 13 +0 NULL NULL NULL NULL 15 +0 NULL NULL NULL NULL 11 +0 NULL NULL NULL NULL 21 +0 NULL NULL NULL NULL 22 +0 NULL NULL NULL NULL 4 +0 NULL NULL NULL NULL 6 +SELECT * FROM graph_base; +from_id to_id +1 2 +2 1 +4 6 +10 11 +10 15 +12 10 +14 13 +15 13 +21 22 +# And delete all references to node 2 +DELETE FROM graph_base WHERE from_id=2; +DELETE FROM graph_base WHERE to_id=2; +SELECT count(*) FROM graph; +count(*) +7 +SELECT count(*) FROM graph_base; +count(*) +7 +SELECT * FROM graph where latch='0'; +latch origid destid weight seq linkid +0 NULL NULL NULL NULL 12 +0 NULL NULL NULL NULL 10 +0 NULL NULL NULL NULL 14 +0 NULL NULL NULL NULL 13 +0 NULL NULL NULL NULL 15 +0 NULL NULL NULL NULL 11 +0 NULL NULL NULL NULL 21 +0 NULL NULL NULL NULL 22 +0 NULL NULL NULL NULL 4 +0 NULL NULL NULL NULL 6 +SELECT * FROM graph_base; +from_id to_id +4 6 +10 11 +10 15 +12 10 +14 13 +15 13 +21 22 +DELETE FROM graph_base; +SELECT count(*) FROM graph; +count(*) +0 +SELECT count(*) FROM graph_base; +count(*) +0 +SELECT * FROM graph where latch='0'; +latch origid destid weight seq linkid +SELECT * FROM graph_base; +from_id to_id +FLUSH TABLES; +TRUNCATE TABLE graph_base; +DROP TABLE graph_base; +DROP TABLE graph; diff --git a/mysql-test/suite/oqgraph/regression_796647c.test b/mysql-test/suite/oqgraph/regression_796647c.test index c45083ade32..e0406122018 100644 --- a/mysql-test/suite/oqgraph/regression_796647c.test +++ b/mysql-test/suite/oqgraph/regression_796647c.test @@ -53,20 +53,25 @@ INSERT INTO graph_base (from_id,to_id) VALUES (4,6); #-- we get a segfault SELECT count(*) FROM graph; SELECT count(*) FROM graph_base; +SELECT * FROM graph where latch='0'; +SELECT * FROM graph_base; ---echo # And delete all references to node 5 -DELETE FROM graph_base WHERE from_id=5; -DELETE FROM graph_base WHERE from_id=3 AND to_id=5; +--echo # And delete all references to node 2 +DELETE FROM graph_base WHERE from_id=2; +DELETE FROM graph_base WHERE to_id=2; -#-- The following queries would currently return incorrect results -#-- 6 rows instead of 21 -#-- Maybe manifestation of https://bugs.launchpad.net/oqgraph/+bug/796647 ---echo # This is currently bogus: SELECT count(*) FROM graph; SELECT count(*) FROM graph_base; +SELECT * FROM graph where latch='0'; +SELECT * FROM graph_base; DELETE FROM graph_base; +SELECT count(*) FROM graph; +SELECT count(*) FROM graph_base; +SELECT * FROM graph where latch='0'; +SELECT * FROM graph_base; + #-- The following line would hang mysqld currently, see bug https://bugs.launchpad.net/oqgraph/+bug/1195735 #-- SELECT * FROM graph; diff --git a/storage/oqgraph/graphcore.cc b/storage/oqgraph/graphcore.cc index ce785b205c3..0b6be1da6af 100644 --- a/storage/oqgraph/graphcore.cc +++ b/storage/oqgraph/graphcore.cc @@ -1111,8 +1111,18 @@ int edges_cursor::fetch_row(const row &row_info, row &result, { result= row_info; result.orig_indicator= result.dest_indicator= result.weight_indicator= 1; - result.orig= get(boost::vertex_index, share->g, source( *edge, share->g ) ); - result.dest= get(boost::vertex_index, share->g, target( *edge, share->g ) ); + + oqgraph3::vertex_id orig = get(boost::vertex_index, share->g, source( *edge, share->g ) ); + oqgraph3::vertex_id dest = get(boost::vertex_index, share->g, target( *edge, share->g ) ); + + // bug 796647c - may be symptomatic of a bigger problem with representation + // but origid and destid can be -1 indicating no such record, NULL? but oqgraph3::vertex_id + // seems to resolve to VertexID (unsigned) in row + // in any case we should check for errors (-1) in origid... because all edges have at least one vertex by definition + assert( ! ((size_t)orig == (size_t)-1 && (size_t)dest == (size_t)-1)); // indicates we havent handle a HA_ERR_RECORD_DELETED somewhere + + result.orig= orig; + result.dest= dest; result.weight= get(boost::edge_weight, share->g, *edge); return oqgraph::OK; } diff --git a/storage/oqgraph/ha_oqgraph.cc b/storage/oqgraph/ha_oqgraph.cc index 8cd15dec2e8..5251d1600eb 100644 --- a/storage/oqgraph/ha_oqgraph.cc +++ b/storage/oqgraph/ha_oqgraph.cc @@ -1050,7 +1050,7 @@ int ha_oqgraph::fill_record(byte *record, const open_query::row &row) int ha_oqgraph::rnd_init(bool scan) { - edges->file->info(HA_STATUS_VARIABLE); // Fix for bug 1195735 - ensure we operate with up to date count! + edges->file->info(HA_STATUS_VARIABLE); // Fix for bug 1195735, hang after truncate table - ensure we operate with up to date count edges->prepare_for_position(); return error_code(graph->random(scan)); } @@ -1060,14 +1060,7 @@ int ha_oqgraph::rnd_next(byte *buf) int res; open_query::row row = {}; - // Problem: bug 1195735 - mysqld hang if we delete * from the underlying table, we get an infinite loop through here - // fetch_row() --> fetch_row() --> num_edges() --> _table->file->stats->records - // _table is actually a handle on the backing table we just deleted everything from. so the statistics are out of date. - // so we really need to force a refresh on the backing store statistics, when starting a new query - // So we probably need to fix this bug in rnd_init - // Note, close() never called in between; this would otherwise clean things up - - if (!(res= graph->fetch_row(row))) // FIXME - this called after DELETE FROM graph_base; hangs... + if (!(res= graph->fetch_row(row))) res= fill_record(buf, row); table->status= res ? STATUS_NOT_FOUND: 0; return error_code(res); diff --git a/storage/oqgraph/oqgraph_thunk.cc b/storage/oqgraph/oqgraph_thunk.cc index d8e05f04af1..8e5cf2f0de7 100644 --- a/storage/oqgraph/oqgraph_thunk.cc +++ b/storage/oqgraph/oqgraph_thunk.cc @@ -235,7 +235,7 @@ int oqgraph3::cursor::restore_position() } oqgraph3::vertex_id oqgraph3::cursor::get_origid() -{ +{ if (_origid) return *_origid; @@ -509,10 +509,14 @@ int oqgraph3::cursor::seek_to( } else { - if (int rc= table.file->ha_rnd_init(true)) + int rc; + if ((rc= table.file->ha_rnd_init(true))) return clear_position(rc); - if (int rc= table.file->ha_rnd_next(table.record[0])) - { + + // We need to skip over any deleted records we encounter. Bug 796647 + while ( ((rc= table.file->ha_rnd_next(table.record[0]))) != 0) { + if (rc == HA_ERR_RECORD_DELETED) + continue; table.file->ha_rnd_end(); return clear_position(rc); }