← Back to team overview

maria-developers team mailing list archive

bzr commit into MariaDB 5.1, with Maria 1.5:maria branch (knielsen:2784)

 

#At lp:maria

 2784 knielsen@xxxxxxxxxxxxxxx	2010-01-04 [merge]
      Merge OQGraph into latest MariaDB trunk.
      added:
        mysql-test/suite/oqgraph/
        mysql-test/suite/oqgraph/include/
        mysql-test/suite/oqgraph/include/have_oqgraph_engine.inc
        mysql-test/suite/oqgraph/r/
        mysql-test/suite/oqgraph/r/basic.result
        mysql-test/suite/oqgraph/t/
        mysql-test/suite/oqgraph/t/basic-master.opt
        mysql-test/suite/oqgraph/t/basic.test
        storage/oqgraph/
        storage/oqgraph/CMakeFiles.txt
        storage/oqgraph/Makefile.am
        storage/oqgraph/graphcore-graph.h
        storage/oqgraph/graphcore-types.h
        storage/oqgraph/graphcore.cc
        storage/oqgraph/graphcore.h
        storage/oqgraph/graphstore.c
        storage/oqgraph/graphstore.h
        storage/oqgraph/ha_oqgraph.cc
        storage/oqgraph/ha_oqgraph.h
        storage/oqgraph/oqgraph_config.h.in
        storage/oqgraph/oqgraph_probes.d
        storage/oqgraph/oqgraph_probes.h
        storage/oqgraph/plug.in
      modified:
        BUILD/SETUP.sh
        mysql-test/mysql-test-run.pl

=== modified file 'BUILD/SETUP.sh'
--- a/BUILD/SETUP.sh	2009-12-06 17:34:54 +0000
+++ b/BUILD/SETUP.sh	2010-01-04 08:47:15 +0000
@@ -210,7 +210,7 @@ if test -z "$CC" ; then
 fi
 
 if test -z "$CXX" ; then
-  CXX=gcc
+  CXX=g++
 fi
 
 # If ccache (a compiler cache which reduces build time)

=== modified file 'mysql-test/mysql-test-run.pl'
--- a/mysql-test/mysql-test-run.pl	2009-12-06 17:34:54 +0000
+++ b/mysql-test/mysql-test-run.pl	2010-01-04 08:47:15 +0000
@@ -126,7 +126,7 @@ my $path_config_file;           # The ge
 # executables will be used by the test suite.
 our $opt_vs_config = $ENV{'MTR_VS_CONFIG'};
 
-my $DEFAULT_SUITES= "main,binlog,federated,rpl,innodb,maria,parts";
+my $DEFAULT_SUITES= "main,binlog,federated,rpl,innodb,maria,parts,oqgraph";
 my $opt_suites;
 
 our $opt_verbose= 0;  # Verbose output, enable with --verbose
@@ -1962,6 +1962,33 @@ sub environment_setup {
     $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=EXAMPLE=".$plugin_filename;
   }
 
+  # --------------------------------------------------------------------------
+  # Add the path where mysqld will find graph_engine.so
+  # --------------------------------------------------------------------------
+  if ($mysql_version_id >= 50100 && !(IS_WINDOWS && $opt_embedded_server)) {
+    my $plugin_filename;
+    if (IS_WINDOWS)
+    {
+       $plugin_filename = "oqgraph_engine.dll";
+    }
+    else
+    {
+       $plugin_filename = "oqgraph_engine.so";
+    }
+    my $lib_oqgraph_plugin=
+      mtr_file_exists(vs_config_dirs('storage/oqgraph',$plugin_filename),
+                      "$basedir/storage/oqgraph/.libs/".$plugin_filename,
+                      "$basedir/lib/mariadb/plugin/".$plugin_filename,
+                      "$basedir/lib/mysql/plugin/".$plugin_filename);
+    $ENV{'OQGRAPH_PLUGIN'}=
+      ($lib_oqgraph_plugin ? basename($lib_oqgraph_plugin) : "");
+    $ENV{'OQGRAPH_PLUGIN_OPT'}= "--plugin-dir=".
+      ($lib_oqgraph_plugin ? dirname($lib_oqgraph_plugin) : "");
+
+    $ENV{'GRAPH_ENGINE_SO'}="'".$plugin_filename."'";
+    $ENV{'OQGRAPH_PLUGIN_LOAD'}="--plugin_load=;OQGRAPH=".$plugin_filename.";";
+  }
+
   # ----------------------------------------------------
   # Add the path where mysqld will find mypluglib.so
   # ----------------------------------------------------

=== added directory 'mysql-test/suite/oqgraph'
=== added directory 'mysql-test/suite/oqgraph/include'
=== added file 'mysql-test/suite/oqgraph/include/have_oqgraph_engine.inc'
--- a/mysql-test/suite/oqgraph/include/have_oqgraph_engine.inc	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/oqgraph/include/have_oqgraph_engine.inc	2010-01-04 08:27:50 +0000
@@ -0,0 +1,4 @@
+disable_query_log;
+--require r/true.require
+select (PLUGIN_LIBRARY LIKE 'oqgraph_engine%') as `TRUE` from information_schema.plugins where PLUGIN_NAME='OQGRAPH';
+enable_query_log;

=== added directory 'mysql-test/suite/oqgraph/r'
=== added file 'mysql-test/suite/oqgraph/r/basic.result'
--- a/mysql-test/suite/oqgraph/r/basic.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/oqgraph/r/basic.result	2010-01-04 08:27:50 +0000
@@ -0,0 +1,63 @@
+drop table if exists graph;
+Warnings:
+Note	1051	Unknown table 'graph'
+CREATE TABLE graph (
+latch   SMALLINT  UNSIGNED 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;
+delete from graph;
+insert into graph(origid, destid) values (1,2), (2,1);
+insert into graph(origid, destid) values (1,3), (3,1);
+insert into graph(origid, destid) values (3,4), (4,3);
+insert into graph(origid, destid) values (3,5), (5,3);
+insert into graph(origid, destid) values (5,6), (6,5);
+select * from graph where latch = 2 and origid = 1 and weight = 1;
+latch	origid	destid	weight	seq	linkid
+2	1	NULL	1	3	3
+2	1	NULL	1	2	2
+select * from graph where latch = 2 and origid = 1 and weight = 2;
+latch	origid	destid	weight	seq	linkid
+2	1	NULL	2	5	5
+2	1	NULL	2	4	4
+select * from graph 
+where latch = 2 and origid = 1 and (weight = 1 or weight = 2);
+latch	origid	destid	weight	seq	linkid
+2	1	NULL	2	5	5
+2	1	NULL	2	4	4
+2	1	NULL	1	3	3
+2	1	NULL	1	2	2
+select * from graph where latch=1 and origid=1 and destid=6;
+latch	origid	destid	weight	seq	linkid
+1	1	6	NULL	0	1
+1	1	6	1	1	3
+1	1	6	1	2	5
+1	1	6	1	3	6
+select * from graph where latch=1 and origid=1 and destid=4;
+latch	origid	destid	weight	seq	linkid
+1	1	4	NULL	0	1
+1	1	4	1	1	3
+1	1	4	1	2	4
+select * from graph where latch=1 and origid=4 and destid=1;
+latch	origid	destid	weight	seq	linkid
+1	4	1	NULL	0	4
+1	4	1	1	1	3
+1	4	1	1	2	1
+insert into graph (origid,destid) values (4,6);
+delete from graph where origid=5;
+delete from graph where origid=3 and destid=5;
+select * from graph where latch=1 and origid=1 and destid=6;
+latch	origid	destid	weight	seq	linkid
+1	1	6	NULL	0	1
+1	1	6	1	1	3
+1	1	6	1	2	4
+1	1	6	1	3	6
+select * from graph where latch=1 and origid=6 and destid=1;
+latch	origid	destid	weight	seq	linkid
+truncate table graph;
+drop table graph;

=== added directory 'mysql-test/suite/oqgraph/t'
=== added file 'mysql-test/suite/oqgraph/t/basic-master.opt'
--- a/mysql-test/suite/oqgraph/t/basic-master.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/oqgraph/t/basic-master.opt	2010-01-04 08:27:50 +0000
@@ -0,0 +1,2 @@
+$OQGRAPH_PLUGIN_OPT
+$OQGRAPH_PLUGIN_LOAD

=== added file 'mysql-test/suite/oqgraph/t/basic.test'
--- a/mysql-test/suite/oqgraph/t/basic.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/oqgraph/t/basic.test	2010-01-04 08:27:50 +0000
@@ -0,0 +1,45 @@
+-- source suite/oqgraph/include/have_oqgraph_engine.inc
+
+drop table if exists graph;
+
+CREATE TABLE graph (
+    latch   SMALLINT  UNSIGNED 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;
+
+delete from graph;
+
+insert into graph(origid, destid) values (1,2), (2,1);
+insert into graph(origid, destid) values (1,3), (3,1);
+insert into graph(origid, destid) values (3,4), (4,3);
+insert into graph(origid, destid) values (3,5), (5,3);
+insert into graph(origid, destid) values (5,6), (6,5);
+
+select * from graph where latch = 2 and origid = 1 and weight = 1;
+
+select * from graph where latch = 2 and origid = 1 and weight = 2;
+
+select * from graph 
+where latch = 2 and origid = 1 and (weight = 1 or weight = 2);
+
+select * from graph where latch=1 and origid=1 and destid=6;
+select * from graph where latch=1 and origid=1 and destid=4;
+select * from graph where latch=1 and origid=4 and destid=1;
+
+insert into graph (origid,destid) values (4,6);
+
+delete from graph where origid=5;
+delete from graph where origid=3 and destid=5;
+
+select * from graph where latch=1 and origid=1 and destid=6;
+select * from graph where latch=1 and origid=6 and destid=1;
+
+truncate table graph;
+
+drop table graph;

=== added directory 'storage/oqgraph'
=== added file 'storage/oqgraph/CMakeFiles.txt'
--- a/storage/oqgraph/CMakeFiles.txt	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/CMakeFiles.txt	2010-01-04 08:27:50 +0000
@@ -0,0 +1,22 @@
+# Copyright (C) 2006 MySQL AB
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql
+                    ${CMAKE_SOURCE_DIR}/regex
+                    ${CMAKE_SOURCE_DIR}/extra/yassl/include)
+ADD_LIBRARY(oqgraph ha_oqgraph.cc)

=== added file 'storage/oqgraph/Makefile.am'
--- a/storage/oqgraph/Makefile.am	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/Makefile.am	2010-01-04 08:27:50 +0000
@@ -0,0 +1,96 @@
+# Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+# ======================================================================
+# Open Query Graph Computation Engine, based on a concept by Arjen Lentz
+# Mk.II implementation by Antony Curtis & Arjen Lentz
+# For more information, documentation, support, enhancement engineering,
+# and non-GPL licensing, see http://openquery.com/graph
+# or contact graph@xxxxxxxxxxxxx
+# For packaged binaries, see http://ourdelta.org
+# ======================================================================
+
+mysqlplugindir=		$(pkglibdir)/plugin
+
+BOOST_CXXFLAGS =	-frtti -fexceptions -fimplicit-templates
+#BOOST_CXXFLAGS+=	-g
+#original flags before 2009-11-10
+#BOOST_CXXFLAGS+=	-O3 -fomit-frame-pointer -fstrict-aliasing
+#BOOST_CXXFLAGS+=	-momit-leaf-frame-pointer -falign-loops
+#modified flags:
+# - remove omit-frame-pointer, x86 specific (fails on PPC) + hinders debugging
+#   Option details from gcc man:
+#   Don't keep the frame pointer in a register for functions that don't need one.
+#   This avoids the instructions to save, set up and restore frame pointers;
+#   it also makes an extra register available in many functions.
+#   It also makes debugging impossible on some machines.
+#   (automatically gets enabled anyway by -O* on some architectures)
+BOOST_CXXFLAGS+=	-O3 -fstrict-aliasing
+BOOST_CXXFLAGS+=	-falign-loops
+BOOST_CXXFLAGS+=	-fvisibility-inlines-hidden
+BOOST_CXXFLAGS+=	-funroll-loops -fno-trapping-math
+
+EXTRA_DIST =	ha_oqgraph.h ha_oqgraph.cc graphcore.cc \
+		graphcore-graph.h graphcore-types.h graphcore.h \
+		CMakeFiles.txt plug.in oqgraph_probes.d
+
+DTRACE =                @DTRACE@
+DTRACEFLAGS =           @DTRACEFLAGS@
+DTRACEFILES =           .libs/liboqgraph_engine_la-ha_oqgraph.o
+
+ORIG_CXXFLAGS = @CXXFLAGS@
+CXXFLAGS=
+noinst_HEADERS = ha_oqgraph.h \
+		 graphcore-graph.h graphcore-types.h graphcore.h \
+		 oqgraph_probes.h
+
+noinst_LTLIBRARIES = libgraphcore.la
+libgraphcore_la_SOURCES = graphcore.cc
+libgraphcore_la_CXXFLAGS = $(ORIG_CXXFLAGS) $(BOOST_CXXFLAGS)
+
+if BUILD_OQGRAPH_FOR_MYSQL
+
+if BUILD_OQGRAPH_STANDALONE
+INCLUDES = -DDBUG_ON -DSAFE_MUTEX -DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC -DSAFE_MUTEX -DHAVE_OQGRAPH $(MYSQL_INC) 
+else
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/regex -I$(top_srcdir)/sql -I$(srcdir) -DHAVE_OQGRAPH 
+endif !BUILD_OQGRAPH_STANDALONE
+
+EXTRA_LTLIBRARIES = oqgraph_engine.la
+mysqlplugin_LTLIBRARIES = @plugin_oqgraph_shared_target@
+oqgraph_engine_la_SOURCES = ha_oqgraph.cc
+oqgraph_engine_la_LIBADD = libgraphcore.la
+
+if HAVE_DTRACE
+  oqgraph_engine_la_LIBADD += oqgraph_probes.o
+endif
+
+oqgraph_engine_la_LDFLAGS =	-module -rpath $(mysqlplugindir)
+oqgraph_engine_la_CFLAGS = $(ORIG_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN
+oqgraph_engine_la_CXXFLAGS = $(ORIG_CXXFLAGS) -DMYSQL_DYNAMIC_PLUGIN
+
+oqgraph_probes.h: oqgraph_probes.d
+	$(DTRACE) $(DTRACEFLAGS) -h -s oqgraph_probes.d
+	mv oqgraph_probes.h oqgraph_probes.h.bak
+	sed "s/#include <unistd.h>//g" oqgraph_probes.h.bak > oqgraph_probes.h
+	rm oqgraph_probes.h.bak
+
+oqgraph_probes.o:
+	$(DTRACE) $(DTRACEFLAGS) -G -s oqgraph_probes.d $(DTRACEFILES)
+
+endif BUILD_OQGRAPH_FOR_MYSQL
+
+# End

=== added file 'storage/oqgraph/graphcore-graph.h'
--- a/storage/oqgraph/graphcore-graph.h	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/graphcore-graph.h	2010-01-04 08:27:50 +0000
@@ -0,0 +1,48 @@
+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/* ======================================================================
+   Open Query Graph Computation Engine, based on a concept by Arjen Lentz
+   Mk.II implementation by Antony Curtis & Arjen Lentz
+   For more information, documentation, support, enhancement engineering,
+   and non-GPL licensing, see http://openquery.com/graph
+   or contact graph@xxxxxxxxxxxxx
+   For packaged binaries, see http://ourdelta.org
+   ======================================================================
+*/
+
+#ifndef oq_graphcore_graph_h_
+#define oq_graphcore_graph_h_
+
+typedef adjacency_list
+<
+  vecS,
+  vecS,
+  bidirectionalS,
+  VertexInfo,
+  EdgeInfo
+> Graph;
+
+#define GRAPH_WEIGHTMAP(G) get(&EdgeInfo::weight, G)
+typedef property_map<Graph, EdgeWeight EdgeInfo::*>::type weightmap_type;
+
+#define GRAPH_INDEXMAP(G)  get(vertex_index, G)
+typedef property_map<Graph, vertex_index_t>::type indexmap_type;
+
+#define GRAPH_IDMAP(G)     get(&VertexInfo::id, G)
+typedef property_map<Graph, VertexID VertexInfo::*>::type idmap_type;
+
+#endif

=== added file 'storage/oqgraph/graphcore-types.h'
--- a/storage/oqgraph/graphcore-types.h	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/graphcore-types.h	2010-01-04 08:27:50 +0000
@@ -0,0 +1,36 @@
+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/* ======================================================================
+   Open Query Graph Computation Engine, based on a concept by Arjen Lentz
+   Mk.II implementation by Antony Curtis & Arjen Lentz
+   For more information, documentation, support, enhancement engineering,
+   and non-GPL licensing, see http://openquery.com/graph
+   or contact graph@xxxxxxxxxxxxx
+   For packaged binaries, see http://ourdelta.org
+   ======================================================================
+*/
+
+#ifndef oq_graphcore_types_h_
+#define oq_graphcore_types_h_
+namespace open_query
+{
+
+  typedef unsigned long long VertexID;
+  typedef double EdgeWeight;
+
+}
+#endif

=== added file 'storage/oqgraph/graphcore.cc'
--- a/storage/oqgraph/graphcore.cc	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/graphcore.cc	2010-01-04 08:27:50 +0000
@@ -0,0 +1,1099 @@
+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/* ======================================================================
+   Open Query Graph Computation Engine, based on a concept by Arjen Lentz
+   Mk.II implementation by Antony Curtis & Arjen Lentz
+   For more information, documentation, support, enhancement engineering,
+   and non-GPL licensing, see http://openquery.com/graph
+   or contact graph@xxxxxxxxxxxxx
+   For packaged binaries, see http://ourdelta.org
+   ======================================================================
+*/
+
+#include <strings.h>
+
+#define BOOST_ALL_NO_LIB 1
+
+#include <boost/config.hpp>
+
+#include <set>
+#include <stack>
+
+#include <boost/property_map.hpp>
+
+#include <boost/graph/graph_concepts.hpp>
+#include <boost/graph/graph_archetypes.hpp>
+#include <boost/graph/adjacency_list.hpp>
+#include <boost/graph/breadth_first_search.hpp>
+#include <boost/graph/dijkstra_shortest_paths.hpp>
+#include <boost/graph/iteration_macros.hpp>
+#include <boost/graph/reverse_graph.hpp>
+#include <boost/graph/graph_utility.hpp>
+
+#include "graphcore.h"
+
+using namespace open_query;
+using namespace boost;
+
+static const row empty_row = { 0 };
+
+namespace open_query
+{
+  enum vertex_id_t { vertex_id };
+
+  struct VertexInfo {
+    inline VertexInfo() { }
+
+    inline VertexInfo(VertexID _id)
+      : id(_id) { }
+
+    VertexID id;
+  };
+
+  struct EdgeInfo {
+    EdgeWeight weight;
+  };
+}
+
+namespace boost
+{
+  BOOST_INSTALL_PROPERTY(vertex, id);
+
+  namespace graph
+  {
+    template<>
+    struct internal_vertex_name<VertexInfo>
+    {
+      typedef multi_index::member<VertexInfo, VertexID, &VertexInfo::id> type;
+    };
+
+    template<>
+    struct internal_vertex_constructor<VertexInfo>
+    {
+      typedef vertex_from_name<VertexInfo> type;
+    };
+  }
+}
+
+namespace open_query
+{
+
+  #include "graphcore-graph.h"
+
+  typedef graph_traits<Graph>::vertex_descriptor Vertex;
+  typedef graph_traits<Graph>::edge_descriptor Edge;
+
+  typedef std::list<std::pair<Vertex,optional<EdgeWeight> > > shortest_path_list;
+  typedef shortest_path_list::iterator shortest_path_iterator;
+
+  template<typename ID, typename IDMap>
+  class id_equals_t
+  {
+  public:
+    id_equals_t(ID id, IDMap map)
+      : m_id(id), m_map(map)
+    { }
+    template<typename V>
+    bool operator()(V u) const
+    {
+      return m_map[u] == m_id;
+    }
+  private:
+    ID m_id;
+    IDMap m_map;
+  };
+
+  template<typename ID, typename IDMap>
+  inline id_equals_t<ID,IDMap>
+  id_equals(ID id, IDMap idmap)
+  {
+    return id_equals_t<ID,IDMap>(id, idmap);
+  }
+
+  template<typename T, typename Graph>
+  class target_equals_t
+  {
+  public:
+    target_equals_t(T target, Graph &g)
+      : m_target(target), m_g(g)
+    { }
+    template<typename V>
+    bool operator()(V u) const
+    {
+      return target(u, m_g) == m_target;
+    }
+  private:
+    T m_target;
+    Graph &m_g;
+  };
+
+  template<typename T, typename Graph>
+  inline target_equals_t<T,Graph>
+  target_equals(T target, Graph &g)
+  {
+    return target_equals_t<T,Graph>(target, g);
+  }
+
+  template<typename T, typename Graph>
+  class source_equals_t
+  {
+  public:
+    source_equals_t(T source, Graph &g)
+      : m_source(source), m_g(g)
+    { }
+    template<typename V>
+    bool operator()(V u) const
+    {
+      return source(u, m_g) == m_source;
+    }
+  private:
+    T m_source;
+    Graph &m_g;
+  };
+
+  template<typename T, typename Graph>
+  inline source_equals_t<T,Graph>
+  source_equals(T source, Graph &g)
+  {
+    return source_equals_t<T,Graph>(source, g);
+  }
+
+  struct reference
+  {
+    int m_flags;
+    int m_sequence;
+    Vertex m_vertex;
+    Edge m_edge;
+    EdgeWeight m_weight;
+
+    enum
+    {
+      HAVE_SEQUENCE = 1,
+      HAVE_WEIGHT = 2,
+      HAVE_EDGE = 4,
+    };
+
+    inline reference()
+      : m_flags(0), m_sequence(0),
+        m_vertex(graph_traits<Graph>::null_vertex()),
+        m_edge(), m_weight(0)
+    { }
+
+    inline reference(int s, Edge e)
+      : m_flags(HAVE_SEQUENCE | HAVE_EDGE), m_sequence(s),
+        m_vertex(graph_traits<Graph>::null_vertex()),
+        m_edge(e), m_weight(0)
+    { }
+
+    inline reference(int s, Vertex v, const optional<Edge> &e,
+                     const optional<EdgeWeight> &w)
+      : m_flags(HAVE_SEQUENCE | (w ? HAVE_WEIGHT : 0) | (e ? HAVE_EDGE : 0)),
+        m_sequence(s), m_vertex(v)
+    {
+      if (w) m_weight= *w;
+      if (e) m_edge= *e;
+    }
+
+    inline reference(int s, Vertex v, Edge e, EdgeWeight w)
+      : m_flags(HAVE_SEQUENCE | HAVE_WEIGHT | HAVE_EDGE),
+        m_sequence(s), m_vertex(v), m_edge(e), m_weight(w)
+    { }
+
+    inline reference(int s, Vertex v, EdgeWeight w)
+      : m_flags(HAVE_SEQUENCE | HAVE_WEIGHT),
+        m_sequence(s), m_vertex(v), m_edge(), m_weight(w)
+    { }
+
+    inline reference(int s, Vertex v)
+      : m_flags(HAVE_SEQUENCE), m_sequence(s), m_vertex(v), m_edge(),
+        m_weight(0)
+    { }
+
+    optional<int> sequence() const
+    {
+      if (m_flags & HAVE_SEQUENCE)
+      {
+        return m_sequence;
+      }
+      return optional<int>();
+    }
+
+    optional<Vertex> vertex() const
+    {
+      if (m_vertex != graph_traits<Graph>::null_vertex())
+        return m_vertex;
+      return optional<Vertex>();
+    }
+
+    optional<Edge> edge() const
+    {
+      if (m_flags & HAVE_EDGE)
+        return m_edge;
+      return optional<Edge>();
+    };
+
+    optional<EdgeWeight> weight() const
+    {
+      if (m_flags & HAVE_WEIGHT)
+        return m_weight;
+      return optional<EdgeWeight>();
+    }
+  };
+}
+
+namespace open_query {
+  class GRAPHCORE_INTERNAL oqgraph_share
+  {
+  public:
+    Graph g;
+
+    weightmap_type weightmap;
+    idmap_type idmap;
+    indexmap_type indexmap;
+
+    optional<Vertex> find_vertex(VertexID id) const;
+    optional<Edge> find_edge(Vertex, Vertex) const;
+
+    inline oqgraph_share() throw()
+      : g(),
+        weightmap(GRAPH_WEIGHTMAP(g)),
+        idmap(GRAPH_IDMAP(g)),
+        indexmap(GRAPH_INDEXMAP(g))
+    { }
+    inline ~oqgraph_share()
+    { }
+  };
+
+  class GRAPHCORE_INTERNAL oqgraph_cursor
+  {
+  public:
+    oqgraph_share *const share;
+
+    inline oqgraph_cursor(oqgraph_share *arg)
+      : share(arg)
+    { }
+    virtual ~oqgraph_cursor()
+    { }
+
+    virtual int fetch_row(const row &, row&) = 0;
+    virtual int fetch_row(const row &, row&, const reference&) = 0;
+    virtual void current(reference& ref) const = 0;
+  };
+}
+
+namespace open_query {
+  class GRAPHCORE_INTERNAL stack_cursor : public oqgraph_cursor
+  {
+  private:
+    optional<EdgeWeight> no_weight;
+  public:
+    int sequence;
+    std::stack<reference> results;
+    reference last;
+
+    inline stack_cursor(oqgraph_share *arg)
+      : oqgraph_cursor(arg), no_weight(), sequence(0), results(), last()
+    { }
+
+    int fetch_row(const row &, row&);
+    int fetch_row(const row &, row&, const reference&);
+
+    void current(reference& ref) const
+    {
+      ref= last;
+    }
+  };
+
+  class GRAPHCORE_INTERNAL vertices_cursor : public oqgraph_cursor
+  {
+    typedef graph_traits<Graph>::vertex_iterator vertex_iterator;
+
+    size_t position;
+    reference last;
+  public:
+    inline vertices_cursor(oqgraph_share *arg)
+      : oqgraph_cursor(arg), position(0)
+    { }
+
+    int fetch_row(const row &, row&);
+    int fetch_row(const row &, row&, const reference&);
+
+    void current(reference& ref) const
+    {
+      ref= last;
+    }
+
+  };
+
+  class GRAPHCORE_INTERNAL edges_cursor : public oqgraph_cursor
+  {
+    typedef graph_traits<Graph>::edge_iterator edge_iterator;
+    typedef edge_iterator::difference_type edge_difference;
+
+    edge_difference position;
+    reference last;
+  public:
+    inline edges_cursor(oqgraph_share *arg)
+      : oqgraph_cursor(arg), position(0), last()
+    { }
+
+    int fetch_row(const row &, row&);
+    int fetch_row(const row &, row&, const reference&);
+
+    void current(reference& ref) const
+    {
+      ref= last;
+    }
+  };
+
+  struct GRAPHCORE_INTERNAL oqgraph_visit_dist
+    : public base_visitor<oqgraph_visit_dist>
+  {
+    typedef on_finish_vertex event_filter;
+
+    oqgraph_visit_dist(std::vector<Vertex>::iterator p,
+                       std::vector<EdgeWeight>::iterator d,
+                       stack_cursor *cursor)
+      : seq(0), m_cursor(*cursor), m_p(p), m_d(d)
+    { assert(cursor); }
+
+    template<class T, class Graph>
+    void operator()(T u, Graph &g)
+    {
+      m_cursor.results.push(reference(++seq, u, m_d[GRAPH_INDEXMAP(g)[u]]));
+    }
+  private:
+    int seq;
+    stack_cursor &m_cursor;
+    std::vector<Vertex>::iterator m_p;
+    std::vector<EdgeWeight>::iterator m_d;
+  };
+
+  template<bool record_weight, typename goal_filter>
+  struct GRAPHCORE_INTERNAL oqgraph_goal
+    : public base_visitor<oqgraph_goal<record_weight,goal_filter> >
+  {
+    typedef goal_filter event_filter;
+
+    oqgraph_goal(Vertex goal, std::vector<Vertex>::iterator p,
+                 stack_cursor *cursor)
+      : m_goal(goal), m_cursor(*cursor), m_p(p)
+    { assert(cursor); }
+
+    template<class T, class Graph>
+    void operator()(T u, Graph &g)
+    {
+      if (u == m_goal)
+      {
+        int seq= 0;
+        indexmap_type indexmap= GRAPH_INDEXMAP(g);
+
+        for (Vertex q, v= u;; v = q, seq++)
+          if ((q= m_p[ indexmap[v] ]) == v)
+            break;
+
+        for (Vertex v= u;; u= v)
+        {
+          optional<Edge> edge;
+          optional<EdgeWeight> weight;
+          v= m_p[ indexmap[u] ];
+          if (record_weight && u != v)
+          {
+            typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
+            for (tie(ei, ei_end)= out_edges(v, g); ei != ei_end; ++ei)
+            {
+              if (target(*ei, g) == u)
+              {
+                edge= *ei;
+                weight= GRAPH_WEIGHTMAP(g)[*ei];
+                break;
+              }
+            }
+          }
+          else if (u != v)
+            weight= 1;
+          m_cursor.results.push(reference(seq--, u, edge, weight));
+          if (u == v)
+            break;
+        }
+        throw this;
+      }
+    }
+
+  private:
+    Vertex m_goal;
+    stack_cursor &m_cursor;
+    std::vector<Vertex>::iterator m_p;
+  };
+}
+
+namespace open_query
+{
+  inline oqgraph::oqgraph(oqgraph_share *arg) throw()
+    : share(arg), cursor(0)
+  { }
+
+  inline oqgraph::~oqgraph() throw()
+  {
+    delete cursor;
+  }
+
+  unsigned oqgraph::edges_count() const throw()
+  {
+    return num_edges(share->g);
+  }
+
+  unsigned oqgraph::vertices_count() const throw()
+  {
+    return num_vertices(share->g);
+  }
+
+  oqgraph* oqgraph::create(oqgraph_share *share) throw()
+  {
+    assert(share != NULL);
+    return new (std::nothrow) oqgraph(share);
+  }
+
+  oqgraph_share* oqgraph::create() throw()
+  {
+    return new (std::nothrow) oqgraph_share();
+  }
+
+  optional<Edge>
+  oqgraph_share::find_edge(Vertex orig, Vertex dest) const
+  {
+    if (in_degree(dest, g) >= out_degree(orig, g))
+    {
+      graph_traits<Graph>::out_edge_iterator ei, ei_end;
+      tie(ei, ei_end)= out_edges(orig, g);
+      if ((ei= find_if(ei, ei_end, target_equals(dest, g))) != ei_end)
+        return *ei;
+    }
+    else
+    {
+      graph_traits<Graph>::in_edge_iterator ei, ei_end;
+      tie(ei, ei_end)= in_edges(dest, g);
+      if ((ei= find_if(ei, ei_end, source_equals(orig, g))) != ei_end)
+        return *ei;
+    }
+    return optional<Edge>();
+  }
+
+  optional<Vertex>
+  oqgraph_share::find_vertex(VertexID id) const
+  {
+    return boost::graph::find_vertex(id, g);
+  }
+
+  int oqgraph::delete_all() throw()
+  {
+    share->g.clear();
+    return 0;
+  }
+
+  int oqgraph::insert_edge(
+      VertexID orig_id, VertexID dest_id, EdgeWeight weight, bool replace) throw()
+  {
+    optional<Vertex> orig, dest;
+    optional<Edge> edge;
+    bool inserted= 0;
+
+    if (weight < 0)
+      return INVALID_WEIGHT;
+    if (!(orig= share->find_vertex(orig_id)))
+    {
+      try
+      {
+        orig= add_vertex(VertexInfo(orig_id), share->g);
+        if (orig == graph_traits<Graph>::null_vertex())
+          return CANNOT_ADD_VERTEX;
+      }
+      catch (...)
+      {
+        return CANNOT_ADD_VERTEX;
+      }
+    }
+    if (!(dest= share->find_vertex(dest_id)))
+    {
+      try
+      {
+        dest= add_vertex(VertexInfo(dest_id), share->g);
+        if (dest == graph_traits<Graph>::null_vertex())
+          return CANNOT_ADD_VERTEX;
+      }
+      catch (...)
+      {
+        return CANNOT_ADD_VERTEX;
+      }
+    }
+    if (!(edge= share->find_edge(*orig, *dest)))
+    {
+      try
+      {
+        tie(edge, inserted)= add_edge(*orig, *dest, share->g);
+        if (!inserted)
+          return CANNOT_ADD_EDGE;
+      }
+      catch (...)
+      {
+        return CANNOT_ADD_EDGE;
+      }
+    }
+    else
+    {
+      if (!replace)
+        return DUPLICATE_EDGE;
+    }
+    share->weightmap[*edge]= weight;
+    return OK;
+  }
+
+  int oqgraph::delete_edge(current_row_st) throw()
+  {
+    reference ref;
+    if (cursor)
+      return EDGE_NOT_FOUND;
+    cursor->current(ref);
+    optional<Edge> edge;
+    if (!(edge= ref.edge()))
+      return EDGE_NOT_FOUND;
+    Vertex orig= source(*edge, share->g);
+    Vertex dest= target(*edge, share->g);
+    remove_edge(*edge, share->g);
+    if (!degree(orig, share->g))
+      remove_vertex(orig, share->g);
+    if (!degree(dest, share->g))
+      remove_vertex(dest, share->g);
+    return OK;
+  }
+
+  int oqgraph::modify_edge(current_row_st,
+      VertexID *orig_id, VertexID *dest_id, EdgeWeight *weight,
+      bool replace) throw()
+  {
+    if (!cursor)
+      return EDGE_NOT_FOUND;
+    reference ref;
+    cursor->current(ref);
+    optional<Edge> edge;
+    if (!(edge= ref.edge()))
+      return EDGE_NOT_FOUND;
+    if (weight && *weight < 0)
+      return INVALID_WEIGHT;
+
+    optional<Vertex> orig= source(*edge, share->g),
+                     dest= target(*edge, share->g);
+
+    bool orig_neq= orig_id ? share->idmap[*orig] != *orig_id : 0;
+    bool dest_neq= dest_id ? share->idmap[*dest] != *dest_id : 0;
+    if (orig_neq || dest_neq)
+    {
+      optional<Edge> new_edge;
+      if (orig_neq && !(orig= share->find_vertex(*orig_id)))
+      {
+        try
+        {
+          orig= add_vertex(VertexInfo(*orig_id), share->g);
+          if (orig == graph_traits<Graph>::null_vertex())
+            return CANNOT_ADD_VERTEX;
+        }
+        catch (...)
+        {
+          return CANNOT_ADD_VERTEX;
+        }
+      }
+      if (dest_neq && !(dest= share->find_vertex(*dest_id)))
+      {
+        try
+        {
+          dest= add_vertex(VertexInfo(*dest_id), share->g);
+          if (dest == graph_traits<Graph>::null_vertex())
+            return CANNOT_ADD_VERTEX;
+        }
+        catch (...)
+        {
+          return CANNOT_ADD_VERTEX;
+        }
+      }
+      if (!(new_edge= share->find_edge(*orig, *dest)))
+      {
+        try
+        {
+          bool inserted;
+          tie(new_edge, inserted)= add_edge(*orig, *dest, share->g);
+          if (!inserted)
+            return CANNOT_ADD_EDGE;
+        }
+        catch (...)
+        {
+          return CANNOT_ADD_EDGE;
+        }
+      }
+      else
+      {
+        if (!replace)
+          return DUPLICATE_EDGE;
+      }
+      share->weightmap[*new_edge]= share->weightmap[*edge];
+      remove_edge(*edge, share->g);
+      edge= new_edge;
+    }
+    if (weight)
+      share->weightmap[*edge]= *weight;
+    return OK;
+  }
+
+  int oqgraph::modify_edge(
+      VertexID orig_id, VertexID dest_id, EdgeWeight weight) throw()
+  {
+    optional<Vertex> orig, dest;
+    optional<Edge> edge;
+
+    if (weight < 0)
+      return INVALID_WEIGHT;
+    if (!(orig= share->find_vertex(orig_id)))
+      return EDGE_NOT_FOUND;
+    if (!(dest= share->find_vertex(dest_id)))
+      return EDGE_NOT_FOUND;
+    if (!(edge= share->find_edge(*orig, *dest)))
+      return EDGE_NOT_FOUND;
+    share->weightmap[*edge]= weight;
+    return OK;
+  }
+
+
+  int oqgraph::delete_edge(VertexID orig_id, VertexID dest_id) throw()
+  {
+    optional<Vertex> orig, dest;
+    optional<Edge> edge;
+
+    if (!(orig= share->find_vertex(orig_id)))
+      return EDGE_NOT_FOUND;
+    if (!(dest= share->find_vertex(dest_id)))
+      return EDGE_NOT_FOUND;
+    if (!(edge= share->find_edge(*orig, *dest)))
+      return EDGE_NOT_FOUND;
+    remove_edge(*edge, share->g);
+    if (!degree(*orig, share->g))
+      remove_vertex(*orig, share->g);
+    if (!degree(*dest, share->g))
+      remove_vertex(*dest, share->g);
+    return OK;
+  }
+
+
+  int oqgraph::search(int *latch, VertexID *orig_id, VertexID *dest_id) throw()
+  {
+      optional<Vertex> orig, dest;
+      int op= 0, seq= 0;
+      enum {
+        NO_SEARCH = 0,
+        DIJKSTRAS = 1,
+        BREADTH_FIRST = 2,
+
+	ALGORITHM = 0x0ffff,
+        HAVE_ORIG = 0x10000,
+        HAVE_DEST = 0x20000,
+      };
+
+      delete cursor; cursor= 0;
+      row_info= empty_row;
+      if ((row_info.latch_indicator= latch))
+        op= ALGORITHM & (row_info.latch= *latch);
+      if ((row_info.orig_indicator= orig_id) && (op|= HAVE_ORIG))
+        orig= share->find_vertex((row_info.orig= *orig_id));
+      if ((row_info.dest_indicator= dest_id) && (op|= HAVE_DEST))
+        dest= share->find_vertex((row_info.dest= *dest_id));
+    //try
+    //{
+      switch (op)
+      {
+      case NO_SEARCH | HAVE_ORIG | HAVE_DEST:
+      case NO_SEARCH | HAVE_ORIG:
+        if ((cursor= new (std::nothrow) stack_cursor(share)) && orig)
+        {
+          graph_traits<Graph>::out_edge_iterator ei, ei_end;
+          for (tie(ei, ei_end)= out_edges(*orig, share->g); ei != ei_end; ++ei)
+          {
+            Vertex v= target(*ei, share->g);
+            static_cast<stack_cursor*>(cursor)->
+                results.push(reference(++seq, v, *ei, share->weightmap[*ei]));
+          }
+        }
+        /* fall through */
+      case NO_SEARCH | HAVE_DEST:
+        if ((op & HAVE_DEST) &&
+            (cursor || (cursor= new (std::nothrow) stack_cursor(share))) &&
+	    dest)
+        {
+          graph_traits<Graph>::in_edge_iterator ei, ei_end;
+          for (tie(ei, ei_end)= in_edges(*dest, share->g); ei != ei_end; ++ei)
+          {
+            Vertex v= source(*ei, share->g);
+            static_cast<stack_cursor*>(cursor)->
+                results.push(reference(++seq, v, *ei, share->weightmap[*ei]));
+          }
+        }
+        break;
+
+      case NO_SEARCH:
+        cursor= new (std::nothrow) vertices_cursor(share);
+        break;
+
+      case DIJKSTRAS | HAVE_ORIG | HAVE_DEST:
+        if ((cursor= new (std::nothrow) stack_cursor(share)) && orig && dest)
+        {
+          std::vector<Vertex> p(num_vertices(share->g));
+          std::vector<EdgeWeight> d(num_vertices(share->g));
+          oqgraph_goal<true, on_finish_vertex>
+              vis(*dest, p.begin(), static_cast<stack_cursor*>(cursor));
+          p[share->indexmap[*orig]]= *orig;
+          try
+          {
+            dijkstra_shortest_paths(share->g, *orig,
+                weight_map(
+                  share->weightmap
+                ).
+                distance_map(
+                    make_iterator_property_map(d.begin(), share->indexmap)
+                ).
+                predecessor_map(
+                    make_iterator_property_map(p.begin(), share->indexmap)
+                ).
+                visitor(
+                    make_dijkstra_visitor(vis)
+                )
+            );
+          }
+          catch (...)
+          { /* printf("found\n"); */ }
+        }
+        break;
+
+      case BREADTH_FIRST | HAVE_ORIG | HAVE_DEST:
+        if ((cursor= new (std::nothrow) stack_cursor(share)) && orig && dest)
+        {
+          std::vector<Vertex> p(num_vertices(share->g));
+          oqgraph_goal<false, on_discover_vertex>
+              vis(*dest, p.begin(), static_cast<stack_cursor*>(cursor));
+          p[share->indexmap[*orig]]= *orig;
+          try
+          {
+            breadth_first_search(share->g, *orig,
+                visitor(make_bfs_visitor(
+                    std::make_pair(
+                        record_predecessors(
+                            make_iterator_property_map(p.begin(), share->indexmap),
+                            on_tree_edge()
+                        ),
+                        vis)
+                    )
+                )
+            );
+          }
+          catch (...)
+          { /* printf("found\n"); */ }
+        }
+        break;
+
+      case DIJKSTRAS | HAVE_ORIG:
+      case BREADTH_FIRST | HAVE_ORIG:
+        if ((cursor= new (std::nothrow) stack_cursor(share)) && (orig || dest))
+        {
+          std::vector<Vertex> p(num_vertices(share->g));
+          std::vector<EdgeWeight> d(num_vertices(share->g));
+          oqgraph_visit_dist vis(p.begin(), d.begin(),
+                                 static_cast<stack_cursor*>(cursor));
+          p[share->indexmap[*orig]]= *orig;
+          switch (ALGORITHM & op)
+          {
+          case DIJKSTRAS:
+            dijkstra_shortest_paths(share->g, *orig,
+                weight_map(
+                  share->weightmap
+                ).
+                distance_map(
+                    make_iterator_property_map(d.begin(), share->indexmap)
+                ).
+                predecessor_map(
+                    make_iterator_property_map(p.begin(), share->indexmap)
+                ).
+                visitor(
+                    make_dijkstra_visitor(vis)
+                )
+            );
+            break;
+          case BREADTH_FIRST:
+            breadth_first_search(share->g, *orig,
+                visitor(make_bfs_visitor(
+                    std::make_pair(
+                        record_predecessors(
+                            make_iterator_property_map(p.begin(),
+                                                       share->indexmap),
+                            on_tree_edge()
+                        ),
+                    std::make_pair(
+                        record_distances(
+                            make_iterator_property_map(d.begin(),
+                                                       share->indexmap),
+                            on_tree_edge()
+                        ),
+                        vis
+                    ))
+                ))
+            );
+            break;
+          default:
+            abort();
+          }
+        }
+        break;
+
+      case BREADTH_FIRST | HAVE_DEST:
+      case DIJKSTRAS | HAVE_DEST:
+        if ((cursor= new (std::nothrow) stack_cursor(share)) && (orig || dest))
+        {
+          std::vector<Vertex> p(num_vertices(share->g));
+          std::vector<EdgeWeight> d(num_vertices(share->g));
+          oqgraph_visit_dist vis(p.begin(), d.begin(),
+                                 static_cast<stack_cursor*>(cursor));
+          reverse_graph<Graph> r(share->g);
+          p[share->indexmap[*dest]]= *dest;
+          switch (ALGORITHM & op)
+          {
+          case DIJKSTRAS:
+            dijkstra_shortest_paths(r, *dest,
+                weight_map(
+                  share->weightmap
+                ).
+                distance_map(
+                    make_iterator_property_map(d.begin(), share->indexmap)
+                ).
+                predecessor_map(
+                    make_iterator_property_map(p.begin(), share->indexmap)
+                ).
+                visitor(
+                    make_dijkstra_visitor(vis)
+                )
+            );
+            break;
+          case BREADTH_FIRST:
+            breadth_first_search(r, *dest,
+                visitor(make_bfs_visitor(
+                    std::make_pair(
+                        record_predecessors(
+                            make_iterator_property_map(p.begin(),
+                                                       share->indexmap),
+                            on_tree_edge()
+                        ),
+                    std::make_pair(
+                        record_distances(
+                            make_iterator_property_map(d.begin(),
+                                                       share->indexmap),
+                            on_tree_edge()
+                        ),
+                        vis
+                    ))
+                ))
+            );
+            break;
+          default:
+            abort();
+          }
+        }
+        break;
+
+      default:
+        break;
+      }
+      return 0;
+    //}
+    //catch (...)
+    //{
+    //  return MISC_FAIL;
+    //}
+  }
+
+  int oqgraph::fetch_row(row& result) throw()
+  {
+    if (!cursor)
+      return NO_MORE_DATA;
+    return cursor->fetch_row(row_info, result);
+  }
+
+  int oqgraph::fetch_row(row& result, const void* ref_ptr) throw()
+  {
+    const reference &ref= *(const reference*) ref_ptr;
+    if (!cursor)
+      return NO_MORE_DATA;
+    return cursor->fetch_row(row_info, result, ref);
+  }
+
+  void oqgraph::row_ref(void *ref_ptr) throw()
+  {
+    reference &ref= *(reference*) ref_ptr;
+    if (cursor)
+      cursor->current(ref);
+    else
+      ref= reference();
+  }
+
+  int oqgraph::random(bool scan) throw()
+  {
+    if (scan || !cursor)
+    {
+      delete cursor; cursor= 0;
+      if (!(cursor= new (std::nothrow) edges_cursor(share)))
+        return MISC_FAIL;
+    }
+    row_info= empty_row;
+    return OK;
+  }
+
+  void oqgraph::free(oqgraph *graph) throw()
+  {
+    delete graph;
+  }
+
+  void oqgraph::free(oqgraph_share *graph) throw()
+  {
+    delete graph;
+  }
+
+  const size_t oqgraph::sizeof_ref= sizeof(reference);
+}
+
+int stack_cursor::fetch_row(const row &row_info, row &result)
+{
+  if (!results.empty())
+  {
+    if (int res= fetch_row(row_info, result, results.top()))
+      return res;
+    results.pop();
+    return oqgraph::OK;
+  }
+  else
+  {
+    last= reference();
+    return oqgraph::NO_MORE_DATA;
+  }
+}
+
+int stack_cursor::fetch_row(const row &row_info, row &result,
+                            const reference &ref)
+{
+  last= ref;
+  if (optional<Vertex> v= last.vertex())
+  {
+    optional<int> seq;
+    optional<EdgeWeight> w;
+    optional<Vertex> v;
+    result= row_info;
+    if ((result.seq_indicator= seq= last.sequence()))
+      result.seq= *seq;
+    if ((result.link_indicator= v= last.vertex()))
+      result.link= share->idmap[*v];
+    if ((result.weight_indicator= w= last.weight()))
+      result.weight= *w;
+    return oqgraph::OK;
+  }
+  else
+    return oqgraph::NO_MORE_DATA;
+}
+
+
+int vertices_cursor::fetch_row(const row &row_info, row &result)
+{
+  vertex_iterator it, end;
+  reference ref;
+  size_t count= position;
+  for (tie(it, end)= vertices(share->g); count && it != end; ++it, --count);
+  if (it != end)
+    ref= reference(position+1, *it);
+  if (int res= fetch_row(row_info, result, ref))
+    return res;
+  position++;
+  return oqgraph::OK;
+}
+
+int vertices_cursor::fetch_row(const row &row_info, row &result,
+                               const reference &ref)
+{
+  last= ref;
+  optional<Vertex> v= last.vertex();
+  result= row_info;
+  if (v)
+  {
+    result.link_indicator= 1;
+    result.link= share->idmap[*v];
+#ifdef DISPLAY_VERTEX_INFO
+    result.seq_indicator= 1;
+    if ((result.seq= degree(*v, share->g)))
+    {
+      EdgeWeight weight= 0;
+      graph_traits<Graph>::in_edge_iterator iei, iei_end;
+      for (tie(iei, iei_end)= in_edges(*v, share->g); iei != iei_end; ++iei)
+        weight+= share->weightmap[*iei];
+      graph_traits<Graph>::out_edge_iterator oei, oei_end;
+      for (tie(oei, oei_end)= out_edges(*v, share->g); oei != oei_end; ++oei)
+        weight+= share->weightmap[*oei];
+      result.weight_indicator= 1;
+      result.weight= weight / result.seq;
+    }
+#endif
+    return oqgraph::OK;
+  }
+  else
+    return oqgraph::NO_MORE_DATA;
+}
+
+int edges_cursor::fetch_row(const row &row_info, row &result)
+{
+  edge_iterator it, end;
+  reference ref;
+  size_t count= position;
+  for (tie(it, end)= edges(share->g); count && it != end; ++it, --count);
+  if (it != end)
+    ref= reference(position+1, *it);
+  if (int res= fetch_row(row_info, result, ref))
+    return res;
+  ++position;
+  return oqgraph::OK;
+}
+
+int edges_cursor::fetch_row(const row &row_info, row &result,
+                            const reference &ref)
+{
+  optional<Edge> edge;
+  if ((edge= (last= ref).edge()))
+  {
+    result= row_info;
+    result.orig_indicator= result.dest_indicator= result.weight_indicator= 1;
+    result.orig= share->idmap[ source( *edge, share->g ) ];
+    result.dest= share->idmap[ target( *edge, share->g ) ];
+    result.weight= share->weightmap[ *edge ];
+    return oqgraph::OK;
+  }
+  return oqgraph::NO_MORE_DATA;
+}
+
+namespace boost {
+  GRAPHCORE_INTERNAL void throw_exception(std::exception const&)
+  {
+    abort();
+  }
+}

=== added file 'storage/oqgraph/graphcore.h'
--- a/storage/oqgraph/graphcore.h	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/graphcore.h	2010-01-04 08:27:50 +0000
@@ -0,0 +1,116 @@
+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/* ======================================================================
+   Open Query Graph Computation Engine, based on a concept by Arjen Lentz
+   Mk.II implementation by Antony Curtis & Arjen Lentz
+   For more information, documentation, support, enhancement engineering,
+   and non-GPL licensing, see http://openquery.com/graph
+   or contact graph@xxxxxxxxxxxxx
+   For packaged binaries, see http://ourdelta.org
+   ======================================================================
+*/
+
+#ifndef oq_graphcore_h_
+#define oq_graphcore_h_
+
+/* #define GRAPHCORE_INTERNAL __attribute__((visibility("hidden"))) */
+#define GRAPHCORE_INTERNAL
+
+#include "graphcore-types.h"
+
+namespace open_query
+{
+  class oqgraph_share;
+  class oqgraph_cursor;
+
+  struct row
+  {
+    bool latch_indicator;
+    bool orig_indicator;
+    bool dest_indicator;
+    bool weight_indicator;
+    bool seq_indicator;
+    bool link_indicator;
+
+    int latch;
+    VertexID orig;
+    VertexID dest;
+    EdgeWeight weight;
+    unsigned seq;
+    VertexID link;
+  };
+
+  class oqgraph
+  {
+    oqgraph_share *const share;
+    oqgraph_cursor *cursor;
+    row row_info;
+
+    inline oqgraph(oqgraph_share*) throw();
+    inline ~oqgraph() throw();
+  public:
+
+    enum error_code
+    {
+      OK= 0,
+      NO_MORE_DATA,
+      EDGE_NOT_FOUND,
+      INVALID_WEIGHT,
+      DUPLICATE_EDGE,
+      CANNOT_ADD_VERTEX,
+      CANNOT_ADD_EDGE,
+      MISC_FAIL
+    };
+
+    struct current_row_st {};
+    static inline current_row_st current_row()
+    { return current_row_st(); }
+
+    unsigned vertices_count() const throw();
+    unsigned edges_count() const throw();
+
+    int delete_all(void) throw();
+
+    int insert_edge(VertexID, VertexID, EdgeWeight, bool=0) throw();
+    int modify_edge(VertexID, VertexID, EdgeWeight) throw();
+    int delete_edge(VertexID, VertexID) throw();
+
+    int modify_edge(current_row_st,
+                    VertexID*, VertexID*, EdgeWeight*, bool=0) throw();
+    int delete_edge(current_row_st) throw();
+
+    int replace_edge(VertexID orig, VertexID dest, EdgeWeight weight) throw()
+    { return insert_edge(orig, dest, weight, true); }
+
+    int search(int*, VertexID*, VertexID*) throw();
+    int random(bool) throw();
+
+    int fetch_row(row&) throw();
+    int fetch_row(row&, const void*) throw();
+    void row_ref(void*) throw();
+
+    static oqgraph* create(oqgraph_share*) throw();
+    static oqgraph_share *create() throw();
+
+    static void free(oqgraph*) throw();
+    static void free(oqgraph_share*) throw();
+
+    static const size_t sizeof_ref;
+  };
+
+}
+#endif

=== added file 'storage/oqgraph/graphstore.c'
--- a/storage/oqgraph/graphstore.c	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/graphstore.c	2010-01-04 08:27:50 +0000
@@ -0,0 +1,356 @@
+/*
+ * Graph Engine - Copyright (C) 2007 by Arjen Lentz (arjen@xxxxxxxxxxxxxxxx)
+ * graphstore.c internal storage system
+ */
+#include <stdlib.h>
+#include <string.h>
+#include <my_global.h>
+#include <my_sys.h>
+#include "graphstore.h"
+
+
+/*
+	create a new vertex, and add it to the list (or start a list)
+	NOTE! gspp is ptr to base ptr
+
+	returns 1 for ok, 0 for error
+*/
+static int _add_vertex (GRAPHSTORE **gspp, GRAPH_VERTEXID id)
+{
+	GRAPHSTORE *newgsp;
+	GRAPHSTORE *gscurp;
+
+	if (gspp == NULL)
+		return 0;
+
+	/* not allowing 0 */
+	if (!id)
+		return 0;
+
+	if (*gspp != NULL) {
+		for (gscurp = *gspp; gscurp != NULL; gscurp = gscurp->next) {
+			if (gscurp->vertex->id == id)
+				return 1;	/* we can ignore, id already exists */
+		}
+	}
+
+	/* allocate and initialise */
+	if ((newgsp = my_malloc(sizeof (GRAPHSTORE),MYF(MY_ZEROFILL))) == NULL)
+		return 0;
+
+	if ((newgsp->vertex = my_malloc(sizeof (GRAPH_VERTEX),MYF(MY_ZEROFILL))) == NULL) {
+		my_free(newgsp,MYF(0));
+		return 0;
+	}
+
+	newgsp->vertex->id = id;
+	/* add new vertex to end of list */
+	if (*gspp != NULL) {
+		for (gscurp = *gspp; gscurp->next != NULL; gscurp = gscurp->next);
+		gscurp->next = newgsp;
+	}
+	else /* new list */
+		*gspp = newgsp;
+
+	/* ok */
+	return 1;
+}
+
+
+/*
+	find a vertex by id
+
+	returns ptr or NULL
+*/
+static GRAPH_VERTEX *_find_vertex (GRAPHSTORE *gsp, GRAPH_VERTEXID id)
+{
+	/* just loop through the list to find id */
+	while (gsp != NULL && gsp->vertex->id != id)
+		gsp = gsp->next;
+
+	/* return ptr to vertex, or NULL */
+	return (gsp != NULL ? gsp->vertex : NULL);
+}
+
+
+/*
+	add edge
+	both vertices must already exist; graphstore_insert() does this
+
+	return 1 for ok, 0 for error (already exists, alloc error, etc)
+*/
+static int _add_edge (GRAPHSTORE *gsp, GRAPH_VERTEXID origid, GRAPH_VERTEXID destid, GRAPH_WEIGHT weight)
+{
+	GRAPH_VERTEX *origvp, *destvp;
+	GRAPH_EDGE	*ep, *newep;
+
+	/* find both vertices */
+	if ((origvp = _find_vertex(gsp,origid)) == NULL ||
+		(destvp = _find_vertex(gsp,destid)) == NULL)
+		return 0;
+
+	/* check if edge already exists */
+	for (ep = origvp->forward_edge; ep != NULL; ep = ep->next_edge) {
+		if (ep->vertex->id == destid)
+			return 0;
+	}
+
+	/* allocate and initialise new edge */
+	if ((newep = my_malloc(sizeof (GRAPH_EDGE),MYF(MY_ZEROFILL))) == NULL)
+		return 0;
+
+	newep->vertex = destvp;
+	newep->weight = weight;
+
+	/* insert new edge at start of chain, that's easiest */
+	ep = origvp->forward_edge;
+	origvp->forward_edge = newep;
+	newep->next_edge = ep;
+
+	/* ok */
+	return 1;
+}
+
+
+/*
+	create a new row, and add it to the graph set (or start set)
+	NOTE! gsetpp is ptr to base ptr
+
+	returns 1 for ok, 0 for error
+*/
+static int _add_graph_set (GRAPH_SET **gsetpp, GRAPH_TUPLE *gtp)
+{
+	GRAPH_SET *newgsetp;
+	GRAPH_SET *gsetcurp;
+
+	if (gsetpp == NULL || gtp == NULL)
+		return 0;
+
+	/* allocate and initialise */
+	if ((newgsetp = my_malloc(sizeof (GRAPH_SET),MYF(MY_ZEROFILL))) == NULL)
+		return 0;
+
+	/* put in the data */
+	memcpy(&newgsetp->tuple,gtp,sizeof (GRAPH_TUPLE));
+
+	/* add new row to end of set */
+	if (*gsetpp != NULL) {
+		for (gsetcurp = *gsetpp; gsetcurp->next != NULL; gsetcurp = gsetcurp->next);
+		gsetcurp->next = newgsetp;
+	}
+	else {	/* new set */
+		*gsetpp = newgsetp;
+	}
+
+	/* ok */
+	return 1;
+}
+
+
+/*
+	free a graph set (release memory)
+
+	returns 1 for ok, 0 for error
+*/
+int free_graph_set (GRAPH_SET *gsetp)
+{
+	GRAPH_SET *nextgsetp;
+
+	if (gsetp == NULL)
+		return 0;
+
+	while (gsetp != NULL) {
+		nextgsetp = gsetp->next;
+		/* free() is a void function, nothing to check */
+		my_free(gsetp,MYF(0));
+		gsetp = nextgsetp;
+	}
+
+	/* ok */
+	return 1;
+}
+
+
+/*
+	insert new data into graphstore
+	this can be either a vertex or an edge, depending on the params
+	NOTE! gspp is ptr to base ptr
+
+	returns 1 for ok, 0 for error
+*/
+int graphstore_insert (GRAPHSTORE **gspp, GRAPH_TUPLE *gtp)
+{
+	if (gspp == NULL)
+		return 0;
+
+	/* if nada or no orig vertex, we can't do anything */
+	if (gtp == NULL || !gtp->origid)
+		return 0;
+
+#if 0
+printf("inserting: origid=%lu destid=%lu weight=%lu\n",gtp->origid,gtp->destid,gtp->weight);
+#endif
+
+	if (!gtp->destid)	/* no edge param so just adding vertex */
+		return _add_vertex(gspp,gtp->origid);
+
+	/*
+		add an edge
+		first add both vertices just in case they didn't yet exist...
+		not checking result there: if there's a prob, _add_edge() will catch.
+	*/
+	_add_vertex(gspp,gtp->origid);
+	_add_vertex(gspp,gtp->destid);
+	return _add_edge(*gspp,gtp->origid,gtp->destid,gtp->weight);
+}
+
+
+/*
+	this is an internal function used by graphstore_query()
+
+	find any path from originating vertex to destid
+	if found, add to the result set on the way back
+	NOTE: recursive function!
+	
+	returns 1 for hit, 0 for nothing, -1 for error
+*/
+int _find_any_path(GRAPH_SET **gsetpp, GRAPH_VERTEXID origid, GRAPH_VERTEXID destid, GRAPH_VERTEX *gvp, GRAPH_SEQ depth)
+{
+	GRAPH_EDGE *gep;
+	GRAPH_TUPLE tup;
+	int res;
+
+	if (gvp->id == destid) {
+		/* found target! */
+		bzero(&tup,sizeof (GRAPH_TUPLE));
+		tup.origid	= origid;
+		tup.destid	= destid;
+		tup.seq		= depth;
+		tup.linkid	= gvp->id;
+		return (_add_graph_set(gsetpp,&tup) ? 1 : -1);
+	}
+
+	/* walk through all edges for this vertex */
+	for (gep = gvp->forward_edge; gep; gep = gep->next_edge) {
+		/* recurse */
+		res = _find_any_path(gsetpp,origid,destid,gep->vertex,depth+1);
+		if (res < 0)
+			return res;
+		if (res > 0) {
+			/* found somewhere below this one, insert ourselves and return */
+			bzero(&tup,sizeof (GRAPH_TUPLE));
+			tup.origid	= origid;
+			tup.destid	= destid;
+			tup.weight  = gep->weight;
+			tup.seq		= depth;
+			tup.linkid	= gvp->id;
+			return (_add_graph_set(gsetpp,&tup) ? 1 : -1);			
+		}
+	}
+
+	/* nothing found but no error */
+	return 0;
+}
+
+
+/*
+	query graphstore
+	latch specifies what operation to perform
+
+	we need to feed the conditions in... (through engine condition pushdown)
+	for now we just presume one condition per field so we just feed in a tuple
+	this also means we can just find constants, not ranges
+
+	return ptr to GRAPH_SET
+	caller must free with free_graph_set()
+*/
+GRAPH_SET *graphstore_query (GRAPHSTORE *gsp, GRAPH_TUPLE *gtp)
+{
+	GRAPH_SET *gsetp = NULL;
+	GRAPH_SET *gsetcurp;
+	GRAPH_SET *newgsetp;
+
+	if (gsp == NULL || gtp == NULL)
+		return (NULL);
+
+	switch (gtp->latch) {
+		case 0: /* return all vertices/edges */
+			{
+				GRAPHSTORE *gscurp;
+				GRAPH_EDGE *gep;
+				GRAPH_TUPLE tup;
+
+				/* walk through all vertices */
+				for (gscurp = gsp; gscurp != NULL; gscurp = gscurp->next) {
+					/* check for condition */
+					if (gtp->origid && gscurp->vertex->id != gtp->origid)
+						continue;
+
+					bzero(&tup,sizeof (GRAPH_TUPLE));
+					tup.origid = gscurp->vertex->id;
+
+					/* no edges? */
+					if (gscurp->vertex->forward_edge == NULL) {
+						/* just add vertex to set */
+						if (!_add_graph_set(&gsetp,&tup)) {
+							if (gsetp != NULL)	/* clean up */
+								my_free(gsetp,MYF(0));
+							return (NULL);
+						}
+					}
+					else {
+						/* walk through all edges */
+						for (gep = gscurp->vertex->forward_edge; gep; gep = gep->next_edge) {
+							tup.destid	= gep->vertex->id;
+							tup.weight	= gep->weight;
+
+							/* just add vertex to set */
+							if (!_add_graph_set(&gsetp,&tup)) {
+								if (gsetp != NULL)	/* clean up */
+									my_free(gsetp,MYF(0));
+								return (NULL);
+							}
+						}
+					}
+				}
+			}
+			break;
+
+		case 1:	/* find a path between origid and destid */
+				/* yes it'll just go with the first path it finds! */
+			{
+				GRAPHSTORE *gscurp;
+				GRAPH_VERTEX *origvp;
+				GRAPH_TUPLE tup;
+
+				if (!gtp->origid || !gtp->destid)
+					return NULL;
+
+				/* find both vertices */
+				if ((origvp = _find_vertex(gsp,gtp->origid)) == NULL ||
+					_find_vertex(gsp,gtp->destid) == NULL)
+					return NULL;
+
+				if (_find_any_path(&gsetp,gtp->origid,gtp->destid,origvp,0) < 0) {	/* error? */
+					if (gsetp != NULL)	/* clean up */
+						my_free(gsetp,MYF(0));
+					return NULL;
+				}
+			}
+			break;
+
+		default:
+			/* this ends up being an empty set */
+			break;
+	}
+
+	/* Fix up latch column with the proper value - to be relationally correct */
+	for (gsetcurp = gsetp; gsetcurp != NULL; gsetcurp = gsetcurp->next)
+		gsetcurp->tuple.latch = gtp->latch;
+
+	return gsetp;
+}
+
+
+
+/* end of graphstore.c */
\ No newline at end of file

=== added file 'storage/oqgraph/graphstore.h'
--- a/storage/oqgraph/graphstore.h	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/graphstore.h	2010-01-04 08:27:50 +0000
@@ -0,0 +1,90 @@
+/*
+ * Graph Engine - Copyright (C) 2007 by Arjen Lentz (arjen@xxxxxxxxxxxxxxxx)
+ * graphstore.h internal storage system
+ */
+//typedef unsigned short uint16;
+//typedef unsigned long long uint64;
+
+
+/*
+	This is essentially what a GRAPH engine table looks like on the MySQL end:
+	CREATE TABLE foo (
+		latch	SMALLINT	UNSIGNED NULL,
+		origid	BIGINT		UNSIGNED NULL,
+		destid	BIGINT		UNSIGNED NULL,
+		weight	BIGINT		UNSIGNED NULL,
+		seq		BIGINT		UNSIGNED NULL,
+		linkid	BIGINT		UNSIGNED NULL
+ 	) ENGINE=OQGRAPH
+*/
+
+
+/*
+	We represent the above in C in the following way:
+*/
+typedef uint16	GRAPH_LATCH;
+typedef uint64	GRAPH_VERTEXID;
+typedef uint64	GRAPH_WEIGHT;
+typedef uint64	GRAPH_SEQ;
+
+typedef struct graph_tuple {
+	GRAPH_LATCH		latch;		/* function 							*/
+	GRAPH_VERTEXID	origid;		/* vertex (should be != 0)				*/
+	GRAPH_VERTEXID	destid;		/* edge									*/
+	GRAPH_WEIGHT	weight;		/* weight								*/
+	GRAPH_SEQ		seq;		/* seq# within (origid)					*/
+	GRAPH_VERTEXID	linkid;		/* current step between origid/destid	*/
+} GRAPH_TUPLE;
+
+typedef struct graph_set {
+	GRAPH_TUPLE			tuple;
+	struct graph_set	*next;
+} GRAPH_SET;
+
+
+/*
+	Internally, sets look nothing like the above
+
+	- We have vertices, connected by edges.
+	- Each vertex' edges are maintained in a linked list.
+	- Edges can be weighted.
+
+	There are some issues with this structure, it'd be a pest to do a delete
+	So for now, let's just not support deletes!
+*/
+/* the below is half-gross and will likely change */
+typedef struct graph_edge {
+	struct graph_vertex {
+		GRAPH_VERTEXID		 id;
+		struct graph_edge	*forward_edge;
+	}					*vertex;
+	GRAPH_WEIGHT	 	 weight;
+	struct graph_edge	*next_edge;
+} GRAPH_EDGE;
+
+typedef struct graph_vertex GRAPH_VERTEX;
+
+
+/*
+	A rough internal storage system for a set
+*/
+/* this below is fully gross and will definitely change */
+typedef struct graphstore {
+	GRAPH_VERTEX		*vertex;	/* changed to ptr when integrating into MySQL */
+	struct graphstore	*next;
+} GRAPHSTORE;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* public function declarations */
+int graphstore_insert (GRAPHSTORE **gspp, GRAPH_TUPLE *gtp);
+GRAPH_SET *graphstore_query (GRAPHSTORE *gsp, GRAPH_TUPLE *gtp);
+int free_graph_set (GRAPH_SET *gsetp);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* end of graphstore.h */
\ No newline at end of file

=== added file 'storage/oqgraph/ha_oqgraph.cc'
--- a/storage/oqgraph/ha_oqgraph.cc	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/ha_oqgraph.cc	2010-01-04 08:27:50 +0000
@@ -0,0 +1,1040 @@
+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
+   Portions of this file copyright (C) 2000-2006 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/* ======================================================================
+   Open Query Graph Computation Engine, based on a concept by Arjen Lentz
+   Mk.II implementation by Antony Curtis & Arjen Lentz
+   For more information, documentation, support, enhancement engineering,
+   and non-GPL licensing, see http://openquery.com/graph
+   or contact graph@xxxxxxxxxxxxx
+   For packaged binaries, see http://ourdelta.org
+   ======================================================================
+*/
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation				// gcc: Class implementation
+#endif
+
+#define MYSQL_SERVER	// to have THD
+#include "mysql_priv.h"
+#if MYSQL_VERSION_ID >= 50100
+#include <mysql/plugin.h>
+#endif
+
+#ifdef HAVE_OQGRAPH
+
+#include "ha_oqgraph.h"
+#include "graphcore.h"
+
+#define OQGRAPH_STATS_UPDATE_THRESHOLD 10
+
+using namespace open_query;
+
+
+struct oqgraph_info_st
+{
+  THR_LOCK lock;
+  oqgraph_share *graph;
+  uint use_count;
+  uint key_stat_version;
+  uint records;
+  bool dropped;
+  char name[FN_REFLEN+1];
+};
+
+static const char oqgraph_description[]=
+  "Open Query Graph Computation Engine, stored in memory "
+  "(http://openquery.com/graph)";
+
+#if MYSQL_VERSION_ID < 50100
+static bool oqgraph_init();
+
+handlerton oqgraph_hton= {
+  "OQGRAPH",
+  SHOW_OPTION_YES,
+  oqgraph_description,
+  DB_TYPE_OQGRAPH,
+  oqgraph_init,
+  0,       /* slot */
+  0,       /* savepoint size. */
+  NULL,    /* close_connection */
+  NULL,    /* savepoint */
+  NULL,    /* rollback to savepoint */
+  NULL,    /* release savepoint */
+  NULL,    /* commit */
+  NULL,    /* rollback */
+  NULL,    /* prepare */
+  NULL,    /* recover */
+  NULL,    /* commit_by_xid */
+  NULL,    /* rollback_by_xid */
+  NULL,    /* create_cursor_read_view */
+  NULL,    /* set_cursor_read_view */
+  NULL,    /* close_cursor_read_view */
+  HTON_NO_FLAGS
+};
+
+#define STATISTIC_INCREMENT(X) \
+statistic_increment(table->in_use->status_var.X, &LOCK_status)
+#define MOVE(X) move_field(X)
+#define RECORDS records
+#else
+#define STATISTIC_INCREMENT(X) ha_statistic_increment(&SSV::X)
+#define MOVE(X) move_field_offset(X)
+#define RECORDS stats.records
+#endif
+
+static HASH oqgraph_open_tables;
+static pthread_mutex_t LOCK_oqgraph;
+static bool oqgraph_init_done= 0;
+
+#if MYSQL_VERSION_ID >= 50130
+#define HASH_KEY_LENGTH size_t
+#else
+#define HASH_KEY_LENGTH uint
+#endif
+
+static uchar* get_key(const uchar *ptr, HASH_KEY_LENGTH *length,
+                      my_bool)
+{
+  const OQGRAPH_INFO *share= (const OQGRAPH_INFO*) ptr;
+  *length= strlen(share->name);
+  return (uchar*) share->name;
+}
+
+#if MYSQL_VERSION_ID >= 50100
+static handler* oqgraph_create_handler(handlerton *hton, TABLE_SHARE *table,
+                                       MEM_ROOT *mem_root)
+{
+  return new (mem_root) ha_oqgraph(hton, table);
+}
+
+static int oqgraph_init(handlerton *hton)
+{
+#else
+static bool oqgraph_init()
+{
+  if (have_oqgraph == SHOW_OPTION_DISABLED)
+    return 1;
+#endif
+  if (pthread_mutex_init(&LOCK_oqgraph, MY_MUTEX_INIT_FAST))
+    goto error;
+  if (hash_init(&oqgraph_open_tables, &my_charset_bin, 32, 0, 0,
+                get_key, 0, 0))
+  {
+    pthread_mutex_destroy(&LOCK_oqgraph);
+    goto error;
+  }
+#if MYSQL_VERSION_ID >= 50100
+  hton->state= SHOW_OPTION_YES;
+  hton->db_type= DB_TYPE_DEFAULT;
+  hton->create= oqgraph_create_handler;
+  hton->flags= HTON_NO_FLAGS;
+#endif
+  oqgraph_init_done= TRUE;
+  return 0;
+error:
+#if MYSQL_VERSION_ID < 50100
+  have_oqgraph= SHOW_OPTION_DISABLED;
+#endif
+  return 1;
+}
+
+#if MYSQL_VERSION_ID >= 50100
+static int oqgraph_fini(void *)
+{
+  hash_free(&oqgraph_open_tables);
+  pthread_mutex_destroy(&LOCK_oqgraph);
+  oqgraph_init_done= FALSE;
+  return 0;
+}
+#endif
+
+static OQGRAPH_INFO *get_share(const char *name, TABLE *table=0)
+{
+  OQGRAPH_INFO *share;
+  uint length= strlen(name);
+
+  safe_mutex_assert_owner(&LOCK_oqgraph);
+  if (!(share= (OQGRAPH_INFO*) hash_search(&oqgraph_open_tables,
+                                           (byte*) name, length)))
+  {
+    if (!table ||
+        !(share= new OQGRAPH_INFO))
+      return 0;
+    share->use_count= share->key_stat_version= share->records= 0;
+    share->dropped= 0;
+    strmov(share->name, name);
+    if (!(share->graph= oqgraph::create()))
+    {
+      delete share;
+      return 0;
+    }
+    if (my_hash_insert(&oqgraph_open_tables, (byte*) share))
+    {
+      oqgraph::free(share->graph);
+      delete share;
+      return 0;
+    }
+    thr_lock_init(&share->lock);
+  }
+  share->use_count++;
+  return share;
+}
+
+static int free_share(OQGRAPH_INFO *share, bool drop=0)
+{
+  safe_mutex_assert_owner(&LOCK_oqgraph);
+  if (!share)
+    return 0;
+  if (drop)
+  {
+    share->dropped= true;
+    hash_delete(&oqgraph_open_tables, (byte*) share);
+  }
+  if (!--share->use_count)
+  {
+    if (share->dropped)
+    {
+      thr_lock_delete(&share->lock);
+      oqgraph::free(share->graph);
+      delete share;
+    }
+  }
+  return 0;
+}
+
+static int error_code(int res)
+{
+  switch (res)
+  {
+  case oqgraph::OK:
+    return 0;
+  case oqgraph::NO_MORE_DATA:
+    return HA_ERR_END_OF_FILE;
+  case oqgraph::EDGE_NOT_FOUND:
+    return HA_ERR_KEY_NOT_FOUND;
+  case oqgraph::INVALID_WEIGHT:
+    return HA_ERR_AUTOINC_ERANGE;
+  case oqgraph::DUPLICATE_EDGE:
+    return HA_ERR_FOUND_DUPP_KEY;
+  case oqgraph::CANNOT_ADD_VERTEX:
+  case oqgraph::CANNOT_ADD_EDGE:
+    return HA_ERR_RECORD_FILE_FULL;
+  case oqgraph::MISC_FAIL:
+  default:
+    return HA_ERR_CRASHED_ON_USAGE;
+  }
+}
+
+/**
+ * Check if table complies with our designated structure
+ *
+ *    ColName    Type      Attributes
+ *    =======    ========  =============
+ *    latch     SMALLINT  UNSIGNED NULL
+ *    origid    BIGINT    UNSIGNED NULL
+ *    destid    BIGINT    UNSIGNED NULL
+ *    weight    DOUBLE    NULL
+ *    seq       BIGINT    UNSIGNED NULL
+ *    linkid    BIGINT    UNSIGNED NULL
+ *    =================================
+ *
+  CREATE TABLE foo (
+    latch   SMALLINT  UNSIGNED 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
+
+ */
+static int oqgraph_check_table_structure (TABLE *table_arg)
+{
+  int i;
+  struct { const char *colname; int coltype; } skel[] = {
+    { "latch" , MYSQL_TYPE_SHORT },
+    { "origid", MYSQL_TYPE_LONGLONG },
+    { "destid", MYSQL_TYPE_LONGLONG },
+    { "weight", MYSQL_TYPE_DOUBLE },
+    { "seq"   , MYSQL_TYPE_LONGLONG },
+    { "linkid", MYSQL_TYPE_LONGLONG },
+  { NULL    , 0}
+  };
+
+  DBUG_ENTER("ha_oqgraph::table_structure_ok");
+
+  Field **field= table_arg->field;
+  for (i= 0; *field && skel[i].colname; i++, field++) {
+    /* Check Column Type */
+    if ((*field)->type() != skel[i].coltype)
+      DBUG_RETURN(-1);
+    if (skel[i].coltype != MYSQL_TYPE_DOUBLE) {
+      /* Check Is UNSIGNED */
+      if (!((*field)->flags & UNSIGNED_FLAG ))
+        DBUG_RETURN(-1);
+    }
+    /* Check THAT  NOT NULL isn't set */
+    if ((*field)->flags & NOT_NULL_FLAG)
+      DBUG_RETURN(-1);
+    /* Check the column name */
+    if (strcmp(skel[i].colname,(*field)->field_name))
+      DBUG_RETURN(-1);
+  }
+
+  if (skel[i].colname || *field || !table_arg->key_info || !table_arg->s->keys)
+    DBUG_RETURN(-1);
+
+  KEY *key= table_arg->key_info;
+  for (uint i= 0; i < table_arg->s->keys; ++i, ++key)
+  {
+    Field **field= table_arg->field;
+    /* check that the first key part is the latch and it is a hash key */
+    if (!(field[0] == key->key_part[0].field &&
+          HA_KEY_ALG_HASH == key->algorithm))
+      DBUG_RETURN(-1);
+    if (key->key_parts == 3)
+    {
+      /* KEY (latch, origid, destid) USING HASH */
+      /* KEY (latch, destid, origid) USING HASH */
+      if (!(field[1] == key->key_part[1].field &&
+            field[2] == key->key_part[2].field) &&
+          !(field[1] == key->key_part[2].field &&
+            field[2] == key->key_part[1].field))
+        DBUG_RETURN(-1);
+    }
+    else
+      DBUG_RETURN(-1);
+  }
+
+  DBUG_RETURN(0);
+}
+
+/*****************************************************************************
+** OQGRAPH tables
+*****************************************************************************/
+
+#if MYSQL_VERSION_ID >= 50100
+ha_oqgraph::ha_oqgraph(handlerton *hton, TABLE_SHARE *table_arg)
+  : handler(hton, table_arg),
+#else
+ha_oqgraph::ha_oqgraph(TABLE *table_arg)
+  : handler(&oqgraph_hton, table_arg),
+#endif
+    share(0), graph(0), records_changed(0), key_stat_version(0)
+{ }
+
+
+static const char *ha_oqgraph_exts[] =
+{
+  NullS
+};
+
+const char **ha_oqgraph::bas_ext() const
+{
+  return ha_oqgraph_exts;
+}
+
+#if MYSQL_VERSION_ID >= 50100
+ulonglong ha_oqgraph::table_flags() const
+#else
+ulong ha_oqgraph::table_flags() const
+#endif
+{
+  return (HA_NO_BLOBS | HA_NULL_IN_KEY |
+          HA_REC_NOT_IN_SEQ | HA_CAN_INSERT_DELAYED);
+}
+
+ulong ha_oqgraph::index_flags(uint inx, uint part, bool all_parts) const
+{
+  return HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR;
+}
+
+int ha_oqgraph::open(const char *name, int mode, uint test_if_locked)
+{
+  pthread_mutex_lock(&LOCK_oqgraph);
+  if ((share = get_share(name, table)))
+  {
+    ref_length= oqgraph::sizeof_ref;
+  }
+
+  if (share)
+  {
+    /* Initialize variables for the opened table */
+    thr_lock_data_init(&share->lock, &lock, NULL);
+
+    graph= oqgraph::create(share->graph);
+
+    /*
+      We cannot run update_key_stats() here because we do not have a
+      lock on the table. The 'records' count might just be changed
+      temporarily at this moment and we might get wrong statistics (Bug
+      #10178). Instead we request for update. This will be done in
+      ha_oqgraph::info(), which is always called before key statistics are
+      used.
+    */
+    key_stat_version= share->key_stat_version-1;
+  }
+  pthread_mutex_unlock(&LOCK_oqgraph);
+
+  return (share ? 0 : 1);
+}
+
+int ha_oqgraph::close(void)
+{
+  pthread_mutex_lock(&LOCK_oqgraph);
+  oqgraph::free(graph); graph= 0;
+  int res= free_share(share);
+  pthread_mutex_unlock(&LOCK_oqgraph);
+  return error_code(res);
+}
+
+void ha_oqgraph::update_key_stats()
+{
+  for (uint i= 0; i < table->s->keys; i++)
+  {
+    KEY *key=table->key_info+i;
+    if (!key->rec_per_key)
+      continue;
+    if (key->algorithm != HA_KEY_ALG_BTREE)
+    {
+      if (key->flags & HA_NOSAME)
+        key->rec_per_key[key->key_parts-1]= 1;
+      else
+      {
+        unsigned vertices= graph->vertices_count();
+        unsigned edges= graph->edges_count();
+        uint no_records= vertices ? 2 * (edges + vertices) / vertices : 2;
+        if (no_records < 2)
+          no_records= 2;
+        key->rec_per_key[key->key_parts-1]= no_records;
+      }
+    }
+  }
+  records_changed= 0;
+  /* At the end of update_key_stats() we can proudly claim they are OK. */
+  key_stat_version= share->key_stat_version;
+}
+
+
+int ha_oqgraph::write_row(byte * buf)
+{
+  int res= oqgraph::MISC_FAIL;
+  Field ** const field= table->field;
+  STATISTIC_INCREMENT(ha_write_count);
+
+#if MYSQL_VERSION_ID >= 50100
+  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+#endif
+  my_ptrdiff_t ptrdiff= buf - table->record[0];
+
+  if (ptrdiff)
+  {
+    field[1]->MOVE(ptrdiff);
+    field[2]->MOVE(ptrdiff);
+    field[3]->MOVE(ptrdiff);
+  }
+
+  if (!field[1]->is_null() && !field[2]->is_null())
+  {
+    VertexID orig_id= (VertexID) field[1]->val_int();
+    VertexID dest_id= (VertexID) field[2]->val_int();
+    EdgeWeight weight= 1;
+
+    if (!field[3]->is_null())
+      weight= (EdgeWeight) field[3]->val_real();
+
+    if (!(res= graph->insert_edge(orig_id, dest_id, weight, replace_dups)))
+    {
+      ++records_changed;
+      share->records++;
+    }
+    if (res == oqgraph::DUPLICATE_EDGE && ignore_dups && !insert_dups)
+      res= oqgraph::OK;
+  }
+
+  if (ptrdiff)
+  {
+    field[1]->MOVE(-ptrdiff);
+    field[2]->MOVE(-ptrdiff);
+    field[3]->MOVE(-ptrdiff);
+  }
+#if MYSQL_VERSION_ID >= 50100
+  dbug_tmp_restore_column_map(table->read_set, old_map);
+#endif
+
+  if (!res && records_changed*OQGRAPH_STATS_UPDATE_THRESHOLD > share->records)
+  {
+    /*
+       We can perform this safely since only one writer at the time is
+       allowed on the table.
+    */
+    share->key_stat_version++;
+  }
+
+  return error_code(res);
+}
+
+int ha_oqgraph::update_row(const byte * old, byte * buf)
+{
+  int res= oqgraph::MISC_FAIL;
+  VertexID orig_id, dest_id;
+  EdgeWeight weight= 1;
+  Field **field= table->field;
+  STATISTIC_INCREMENT(ha_update_count);
+
+#if MYSQL_VERSION_ID >= 50100
+  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+#endif
+  my_ptrdiff_t ptrdiff= buf - table->record[0];
+
+  if (ptrdiff)
+  {
+    field[0]->MOVE(ptrdiff);
+    field[1]->MOVE(ptrdiff);
+    field[2]->MOVE(ptrdiff);
+    field[3]->MOVE(ptrdiff);
+  }
+
+  if (inited == INDEX || inited == RND)
+  {
+    VertexID *origp= 0, *destp= 0;
+    EdgeWeight *weightp= 0;
+    if (!field[1]->is_null())
+      *(origp= &orig_id)= (VertexID) field[1]->val_int();
+    if (!field[2]->is_null())
+      *(destp= &dest_id)= (VertexID) field[2]->val_int();
+    if (!field[3]->is_null())
+      *(weightp= &weight)= (EdgeWeight) field[3]->val_real();
+
+    my_ptrdiff_t ptrdiff2= old - buf;
+
+    field[0]->MOVE(ptrdiff2);
+    field[1]->MOVE(ptrdiff2);
+    field[2]->MOVE(ptrdiff2);
+    field[3]->MOVE(ptrdiff2);
+
+    if (field[0]->is_null())
+    {
+      if (!origp == field[1]->is_null() &&
+          *origp == (VertexID) field[1]->val_int())
+        origp= 0;
+      if (!destp == field[2]->is_null() &&
+          *destp == (VertexID) field[2]->val_int())
+        origp= 0;
+      if (!weightp == field[3]->is_null() &&
+          *weightp == (VertexID) field[3]->val_real())
+        weightp= 0;
+
+      if (!(res= graph->modify_edge(oqgraph::current_row(),
+                                    origp, destp, weightp, replace_dups)))
+        ++records_changed;
+      else if (ignore_dups && res == oqgraph::DUPLICATE_EDGE)
+        res= oqgraph::OK;
+    }
+
+    field[0]->MOVE(-ptrdiff2);
+    field[1]->MOVE(-ptrdiff2);
+    field[2]->MOVE(-ptrdiff2);
+    field[3]->MOVE(-ptrdiff2);
+  }
+
+  if (ptrdiff)
+  {
+    field[0]->MOVE(-ptrdiff);
+    field[1]->MOVE(-ptrdiff);
+    field[2]->MOVE(-ptrdiff);
+    field[3]->MOVE(-ptrdiff);
+  }
+#if MYSQL_VERSION_ID >= 50100
+  dbug_tmp_restore_column_map(table->read_set, old_map);
+#endif
+
+  if (!res && records_changed*OQGRAPH_STATS_UPDATE_THRESHOLD > share->records)
+  {
+    /*
+       We can perform this safely since only one writer at the time is
+       allowed on the table.
+    */
+    share->key_stat_version++;
+  }
+  return error_code(res);
+}
+
+int ha_oqgraph::delete_row(const byte * buf)
+{
+  int res= oqgraph::EDGE_NOT_FOUND;
+  Field **field= table->field;
+  STATISTIC_INCREMENT(ha_delete_count);
+
+  if (inited == INDEX || inited == RND)
+  {
+    if ((res= graph->delete_edge(oqgraph::current_row())) == oqgraph::OK)
+    {
+      ++records_changed;
+      share->records--;
+    }
+  }
+  if (res != oqgraph::OK)
+  {
+#if MYSQL_VERSION_ID >= 50100
+    my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+#endif
+    my_ptrdiff_t ptrdiff= buf - table->record[0];
+
+    if (ptrdiff)
+    {
+      field[0]->MOVE(ptrdiff);
+      field[1]->MOVE(ptrdiff);
+      field[2]->MOVE(ptrdiff);
+    }
+
+    if (field[0]->is_null() && !field[1]->is_null() && !field[2]->is_null())
+    {
+      VertexID orig_id= (VertexID) field[1]->val_int();
+      VertexID dest_id= (VertexID) field[2]->val_int();
+
+      if ((res= graph->delete_edge(orig_id, dest_id)) == oqgraph::OK)
+      {
+        ++records_changed;
+        share->records--;
+      }
+    }
+
+    if (ptrdiff)
+    {
+      field[0]->MOVE(-ptrdiff);
+      field[1]->MOVE(-ptrdiff);
+      field[2]->MOVE(-ptrdiff);
+    }
+#if MYSQL_VERSION_ID >= 50100
+    dbug_tmp_restore_column_map(table->read_set, old_map);
+#endif
+  }
+
+  if (!res && table->s->tmp_table == NO_TMP_TABLE &&
+      records_changed*OQGRAPH_STATS_UPDATE_THRESHOLD > share->records)
+  {
+    /*
+       We can perform this safely since only one writer at the time is
+       allowed on the table.
+    */
+    share->key_stat_version++;
+  }
+  return error_code(res);
+}
+
+int ha_oqgraph::index_read(byte * buf, const byte * key, uint key_len,
+			enum ha_rkey_function find_flag)
+{
+  DBUG_ASSERT(inited==INDEX);
+  return index_read_idx(buf, active_index, key, key_len, find_flag);
+}
+
+int ha_oqgraph::index_next_same(byte *buf, const byte *key, uint key_len)
+{
+  int res;
+  open_query::row row;
+  DBUG_ASSERT(inited==INDEX);
+  STATISTIC_INCREMENT(ha_read_key_count);
+  if (!(res= graph->fetch_row(row)))
+    res= fill_record(buf, row);
+  table->status= res ? STATUS_NOT_FOUND : 0;
+  return error_code(res);
+}
+
+int ha_oqgraph::index_read_idx(byte * buf, uint index, const byte * key,
+			    uint key_len, enum ha_rkey_function find_flag)
+{
+  Field **field= table->field;
+  KEY *key_info= table->key_info + index;
+  int res;
+  VertexID orig_id, dest_id;
+  int latch;
+  VertexID *orig_idp=0, *dest_idp=0;
+  int *latchp=0;
+  open_query::row row;
+  STATISTIC_INCREMENT(ha_read_key_count);
+
+  bmove_align(buf, table->s->default_values, table->s->reclength);
+  key_restore(buf, (byte*) key, key_info, key_len);
+
+#if MYSQL_VERSION_ID >= 50100
+  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
+#endif
+  my_ptrdiff_t ptrdiff= buf - table->record[0];
+
+  if (ptrdiff)
+  {
+    field[0]->MOVE(ptrdiff);
+    field[1]->MOVE(ptrdiff);
+    field[2]->MOVE(ptrdiff);
+  }
+
+  if (!field[0]->is_null())
+  {
+    latch= (int) field[0]->val_int();
+    latchp= &latch;
+  }
+
+  if (!field[1]->is_null())
+  {
+    orig_id= (VertexID) field[1]->val_int();
+    orig_idp= &orig_id;
+  }
+
+  if (!field[2]->is_null())
+  {
+    dest_id= (VertexID) field[2]->val_int();
+    dest_idp= &dest_id;
+  }
+
+  if (ptrdiff)
+  {
+    field[0]->MOVE(-ptrdiff);
+    field[1]->MOVE(-ptrdiff);
+    field[2]->MOVE(-ptrdiff);
+  }
+#if MYSQL_VERSION_ID >= 50100
+  dbug_tmp_restore_column_map(table->read_set, old_map);
+#endif
+
+  res= graph->search(latchp, orig_idp, dest_idp);
+
+  if (!res && !(res= graph->fetch_row(row)))
+    res= fill_record(buf, row);
+  table->status = res ? STATUS_NOT_FOUND : 0;
+  return error_code(res);
+}
+
+int ha_oqgraph::fill_record(byte *record, const open_query::row &row)
+{
+  Field **field= table->field;
+
+  bmove_align(record, table->s->default_values, table->s->reclength);
+
+#if MYSQL_VERSION_ID >= 50100
+  my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
+#endif
+  my_ptrdiff_t ptrdiff= record - table->record[0];
+
+  if (ptrdiff)
+  {
+    field[0]->MOVE(ptrdiff);
+    field[1]->MOVE(ptrdiff);
+    field[2]->MOVE(ptrdiff);
+    field[3]->MOVE(ptrdiff);
+    field[4]->MOVE(ptrdiff);
+    field[5]->MOVE(ptrdiff);
+  }
+
+  // just each field specifically, no sense iterating
+  if (row.latch_indicator)
+  {
+    field[0]->set_notnull();
+    field[0]->store((longlong) row.latch);
+  }
+
+  if (row.orig_indicator)
+  {
+    field[1]->set_notnull();
+    field[1]->store((longlong) row.orig);
+  }
+
+  if (row.dest_indicator)
+  {
+    field[2]->set_notnull();
+    field[2]->store((longlong) row.dest);
+  }
+
+  if (row.weight_indicator)
+  {
+    field[3]->set_notnull();
+    field[3]->store((double) row.weight);
+  }
+
+  if (row.seq_indicator)
+  {
+    field[4]->set_notnull();
+    field[4]->store((longlong) row.seq);
+  }
+
+  if (row.link_indicator)
+  {
+    field[5]->set_notnull();
+    field[5]->store((longlong) row.link);
+  }
+
+  if (ptrdiff)
+  {
+    field[0]->MOVE(-ptrdiff);
+    field[1]->MOVE(-ptrdiff);
+    field[2]->MOVE(-ptrdiff);
+    field[3]->MOVE(-ptrdiff);
+    field[4]->MOVE(-ptrdiff);
+    field[5]->MOVE(-ptrdiff);
+  }
+#if MYSQL_VERSION_ID >= 50100
+  dbug_tmp_restore_column_map(table->write_set, old_map);
+#endif
+
+  return 0;
+}
+
+int ha_oqgraph::rnd_init(bool scan)
+{
+  return error_code(graph->random(scan));
+}
+
+int ha_oqgraph::rnd_next(byte *buf)
+{
+  int res;
+  open_query::row row;
+  STATISTIC_INCREMENT(ha_read_rnd_next_count);
+  if (!(res= graph->fetch_row(row)))
+    res= fill_record(buf, row);
+  table->status= res ? STATUS_NOT_FOUND: 0;
+  return error_code(res);
+}
+
+int ha_oqgraph::rnd_pos(byte * buf, byte *pos)
+{
+  int res;
+  open_query::row row;
+  STATISTIC_INCREMENT(ha_read_rnd_count);
+  if (!(res= graph->fetch_row(row, pos)))
+    res= fill_record(buf, row);
+  table->status=res ? STATUS_NOT_FOUND: 0;
+  return error_code(res);
+}
+
+void ha_oqgraph::position(const byte *record)
+{
+  graph->row_ref((void*) ref);	// Ref is aligned
+}
+
+int ha_oqgraph::cmp_ref(const byte *ref1, const byte *ref2)
+{
+  return memcmp(ref1, ref2, oqgraph::sizeof_ref);
+}
+
+int ha_oqgraph::info(uint flag)
+{
+  RECORDS= graph->vertices_count() + graph->edges_count();
+#if 0
+  records= hp_info.records;
+  deleted= hp_info.deleted;
+  errkey=  hp_info.errkey;
+  mean_rec_length= hp_info.reclength;
+  data_file_length= hp_info.data_length;
+  index_file_length= hp_info.index_length;
+  max_data_file_length= hp_info.max_records* hp_info.reclength;
+  delete_length= hp_info.deleted * hp_info.reclength;
+#endif
+  /*
+    If info() is called for the first time after open(), we will still
+    have to update the key statistics. Hoping that a table lock is now
+    in place.
+  */
+  if (key_stat_version != share->key_stat_version)
+    update_key_stats();
+  return 0;
+}
+
+int ha_oqgraph::extra(enum ha_extra_function operation)
+{
+  switch (operation)
+  {
+  case HA_EXTRA_IGNORE_DUP_KEY:
+    ignore_dups= true;
+    break;
+  case HA_EXTRA_NO_IGNORE_DUP_KEY:
+    ignore_dups= false;
+    insert_dups= false;
+    break;
+  case HA_EXTRA_WRITE_CAN_REPLACE:
+    replace_dups= true;
+    break;
+  case HA_EXTRA_WRITE_CANNOT_REPLACE:
+    replace_dups= false;
+    break;
+  case HA_EXTRA_INSERT_WITH_UPDATE:
+    insert_dups= true;
+    break;
+  default:
+    break;
+  }
+  return 0;
+}
+
+int ha_oqgraph::delete_all_rows()
+{
+  int res;
+  if (!(res= graph->delete_all()))
+  {
+    share->records= 0;
+  }
+
+  if (!res && table->s->tmp_table == NO_TMP_TABLE)
+  {
+    /*
+       We can perform this safely since only one writer at the time is
+       allowed on the table.
+    */
+    share->key_stat_version++;
+  }
+  return error_code(res);
+}
+
+int ha_oqgraph::external_lock(THD *thd, int lock_type)
+{
+  return 0;					// No external locking
+}
+
+
+THR_LOCK_DATA **ha_oqgraph::store_lock(THD *thd,
+				       THR_LOCK_DATA **to,
+				       enum thr_lock_type lock_type)
+{
+  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
+    lock.type=lock_type;
+  *to++= &lock;
+  return to;
+}
+
+/*
+  We have to ignore ENOENT entries as the HEAP table is created on open and
+  not when doing a CREATE on the table.
+*/
+
+int ha_oqgraph::delete_table(const char *name)
+{
+  int res= 0;
+  OQGRAPH_INFO *share;
+  pthread_mutex_lock(&LOCK_oqgraph);
+  if ((share= get_share(name)))
+  {
+    res= free_share(share, true);
+  }
+  pthread_mutex_unlock(&LOCK_oqgraph);
+  return error_code(res);
+}
+
+int ha_oqgraph::rename_table(const char * from, const char * to)
+{
+  pthread_mutex_lock(&LOCK_oqgraph);
+  if (OQGRAPH_INFO *share= get_share(from))
+  {
+    strmov(share->name, to);
+    hash_update(&oqgraph_open_tables, (byte*) share,
+                (byte*) from, strlen(from));
+  }
+  pthread_mutex_unlock(&LOCK_oqgraph);
+  return 0;
+}
+
+
+ha_rows ha_oqgraph::records_in_range(uint inx, key_range *min_key,
+                                  key_range *max_key)
+{
+  KEY *key=table->key_info+inx;
+  //if (key->algorithm == HA_KEY_ALG_BTREE)
+  //  return btree_records_in_range(file, inx, min_key, max_key);
+
+  if (!min_key || !max_key ||
+      min_key->length != max_key->length ||
+      min_key->length < key->key_length - key->key_part[2].store_length ||
+      min_key->flag != HA_READ_KEY_EXACT ||
+      max_key->flag != HA_READ_AFTER_KEY)
+  {
+    if (min_key->length == key->key_part[0].store_length)
+    {
+      // If latch is not null and equals 0, return # nodes
+      DBUG_ASSERT(key->key_part[0].store_length == 3);
+      if (key->key_part[0].null_bit && !min_key->key[0] &&
+          !min_key->key[1] && !min_key->key[2])
+        return graph->vertices_count();
+    }
+    return HA_POS_ERROR;			// Can only use exact keys
+  }
+
+  if (RECORDS <= 1)
+    return RECORDS;
+
+  /* Assert that info() did run. We need current statistics here. */
+  DBUG_ASSERT(key_stat_version == share->key_stat_version);
+  ha_rows result= key->rec_per_key[key->key_parts-1];
+
+  return result;
+}
+
+
+int ha_oqgraph::create(const char *name, TABLE *table_arg,
+		    HA_CREATE_INFO *create_info)
+{
+  int res = -1;
+  OQGRAPH_INFO *share;
+
+  pthread_mutex_lock(&LOCK_oqgraph);
+  if ((share= get_share(name)))
+  {
+    free_share(share);
+  }
+  else
+  {
+    if (!oqgraph_check_table_structure(table_arg))
+      res= 0;;
+  }
+  pthread_mutex_unlock(&LOCK_oqgraph);
+
+  if (this->share)
+    info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
+  return error_code(res);
+}
+
+
+void ha_oqgraph::update_create_info(HA_CREATE_INFO *create_info)
+{
+  table->file->info(HA_STATUS_AUTO);
+  //if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
+  //  create_info->auto_increment_value= auto_increment_value;
+}
+
+#if MYSQL_VERSION_ID >= 50100
+struct st_mysql_storage_engine oqgraph_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+mysql_declare_plugin(oqgraph)
+{
+  MYSQL_STORAGE_ENGINE_PLUGIN,
+  &oqgraph_storage_engine,
+  "OQGRAPH",
+  "Arjen Lentz & Antony T Curtis, Open Query",
+  oqgraph_description,
+  PLUGIN_LICENSE_GPL,
+  (int (*)(void*)) oqgraph_init, /* Plugin Init                  */
+  oqgraph_fini,               /* Plugin Deinit                   */
+  0x0200,                     /* Version: 2.0                    */
+  NULL,                       /* status variables                */
+  NULL,                       /* system variables                */
+  NULL                        /* config options                  */
+}
+mysql_declare_plugin_end;
+#endif
+
+#endif

=== added file 'storage/oqgraph/ha_oqgraph.h'
--- a/storage/oqgraph/ha_oqgraph.h	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/ha_oqgraph.h	2010-01-04 08:27:50 +0000
@@ -0,0 +1,114 @@
+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
+   Portions of this file copyright (C) 2000-2006 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/* ======================================================================
+   Open Query Graph Computation Engine, based on a concept by Arjen Lentz
+   Mk.II implementation by Antony Curtis & Arjen Lentz
+   For more information, documentation, support, enhancement engineering,
+   and non-GPL licensing, see http://openquery.com/graph
+   or contact graph@xxxxxxxxxxxxx
+   For packaged binaries, see http://ourdelta.org
+   ======================================================================
+*/
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface			/* gcc class implementation */
+#endif
+
+
+typedef struct oqgraph_info_st OQGRAPH_INFO;
+
+#if MYSQL_VERSION_ID >= 50120
+typedef uchar byte;
+#endif
+
+namespace open_query
+{
+  struct row;
+  class oqgraph;
+}
+
+/* class for the the Open Query Graph handler */
+
+class ha_oqgraph: public handler
+{
+  OQGRAPH_INFO *share;
+  open_query::oqgraph *graph;
+  THR_LOCK_DATA lock;
+  /* number of records changed since last statistics update */
+  uint records_changed;
+  uint key_stat_version;
+  bool replace_dups, ignore_dups, insert_dups;
+
+  int fill_record(byte*, const open_query::row&);
+
+public:
+#if MYSQL_VERSION_ID >= 50100
+  ha_oqgraph(handlerton *hton, TABLE_SHARE *table);
+  ulonglong table_flags() const;
+#else
+  ha_oqgraph(TABLE *table);
+  ulong table_flags() const;
+#endif
+  ~ha_oqgraph() {}
+  const char *table_type() const
+  {
+    return "OQGRAPH";
+  }
+  const char *index_type(uint inx)
+  {
+    return "HASH";
+  }
+  /* Rows also use a fixed-size format */
+  enum row_type get_row_type() const { return ROW_TYPE_FIXED; }
+  const char **bas_ext() const;
+  ulong index_flags(uint inx, uint part, bool all_parts) const;
+  uint max_supported_keys()          const { return MAX_KEY; }
+  uint max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
+  double scan_time() { return (double) 1000000000; }
+  double read_time(uint index, uint ranges, ha_rows rows)
+  { return 1; }
+
+  int open(const char *name, int mode, uint test_if_locked);
+  int close(void);
+  int write_row(byte * buf);
+  int update_row(const byte * old_data, byte * new_data);
+  int delete_row(const byte * buf);
+  int index_read(byte * buf, const byte * key,
+		 uint key_len, enum ha_rkey_function find_flag);
+  int index_read_idx(byte * buf, uint idx, const byte * key,
+		     uint key_len, enum ha_rkey_function find_flag);
+  int index_next_same(byte * buf, const byte * key, uint key_len);
+  int rnd_init(bool scan);
+  int rnd_next(byte *buf);
+  int rnd_pos(byte * buf, byte *pos);
+  void position(const byte *record);
+  int info(uint);
+  int extra(enum ha_extra_function operation);
+  int external_lock(THD *thd, int lock_type);
+  int delete_all_rows(void);
+  ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
+  int delete_table(const char *from);
+  int rename_table(const char * from, const char * to);
+  int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
+  void update_create_info(HA_CREATE_INFO *create_info);
+
+  THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+			     enum thr_lock_type lock_type);
+  int cmp_ref(const byte *ref1, const byte *ref2);
+private:
+  void update_key_stats();
+};

=== added file 'storage/oqgraph/oqgraph_config.h.in'
--- a/storage/oqgraph/oqgraph_config.h.in	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/oqgraph_config.h.in	2010-01-04 08:27:50 +0000
@@ -0,0 +1,73 @@
+/* src/oqgraph_config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Enables DTRACE Support */
+#undef HAVE_DTRACE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <syslimits.h> header file. */
+#undef HAVE_SYSLIMITS_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Source directory for MySQL */
+#undef MYSQL_SRC
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t

=== added file 'storage/oqgraph/oqgraph_probes.d'
--- a/storage/oqgraph/oqgraph_probes.d	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/oqgraph_probes.d	2010-01-04 08:27:50 +0000
@@ -0,0 +1,19 @@
+/* Copyright (C) 2004-2005 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
+
+provider oqgraph {
+	probe open();
+	probe close();
+};

=== added file 'storage/oqgraph/oqgraph_probes.h'
--- a/storage/oqgraph/oqgraph_probes.h	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/oqgraph_probes.h	2010-01-04 08:27:50 +0000
@@ -0,0 +1,45 @@
+/*
+ * Generated by dtrace(1M).
+ */
+
+#ifndef	_OQGRAPH_PROBES_H
+#define	_OQGRAPH_PROBES_H
+
+
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#if _DTRACE_VERSION
+
+#define	OQGRAPH_CLOSE() \
+	__dtrace_oqgraph___close()
+#define	OQGRAPH_CLOSE_ENABLED() \
+	__dtraceenabled_oqgraph___close()
+#define	OQGRAPH_OPEN() \
+	__dtrace_oqgraph___open()
+#define	OQGRAPH_OPEN_ENABLED() \
+	__dtraceenabled_oqgraph___open()
+
+
+extern void __dtrace_oqgraph___close(void);
+extern int __dtraceenabled_oqgraph___close(void);
+extern void __dtrace_oqgraph___open(void);
+extern int __dtraceenabled_oqgraph___open(void);
+
+#else
+
+#define	OQGRAPH_CLOSE()
+#define	OQGRAPH_CLOSE_ENABLED() (0)
+#define	OQGRAPH_OPEN()
+#define	OQGRAPH_OPEN_ENABLED() (0)
+
+#endif
+
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _OQGRAPH_PROBES_H */

=== added file 'storage/oqgraph/plug.in'
--- a/storage/oqgraph/plug.in	1970-01-01 00:00:00 +0000
+++ b/storage/oqgraph/plug.in	2010-01-04 08:27:50 +0000
@@ -0,0 +1,32 @@
+MYSQL_STORAGE_ENGINE(oqgraph,,[Graph Storage Engine],
+        [Open Query Graph Computation Engine], [])
+MYSQL_PLUGIN_DYNAMIC(oqgraph,   [oqgraph_engine.la])
+MYSQL_PLUGIN_DEPENDS_ON_MYSQL_INTERNALS(oqgraph, [ha_oqgraph.cc])
+AM_CONDITIONAL([BUILD_OQGRAPH_FOR_MYSQL], true)
+AM_CONDITIONAL([BUILD_OQGRAPH_STANDALONE], false)
+AM_CONDITIONAL([HAVE_DTRACE], false)
+
+AC_LANG_PUSH([C++])
+AC_CHECK_HEADER([boost/graph/properties.hpp],[:],[
+  mysql_plugin_oqgraph=no
+  with_plugin_oqgraph=no
+])
+
+save_CXXFLAGS="${CXXFLAGS}"
+CXXFLAGS="-fexceptions -fimplicit-templates -O3 -fstrict-aliasing -falign-loops -fvisibility-inlines-hidden -funroll-loops -fno-trapping-math"
+
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+  #include <boost/graph/graph_traits.hpp>
+  #include <boost/graph/adjacency_list.hpp>
+  #include <boost/graph/dijkstra_shortest_paths.hpp>
+
+  using namespace boost;
+]],[[
+  typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
+  Graph g(10);
+]])],[],[
+  mysql_plugin_oqgraph=no
+  with_plugin_oqgraph=no
+])
+CXXFLAGS="${save_CXXFLAGS}"
+AC_LANG_POP()