mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 19:06:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			1216 lines
		
	
	
	
		
			35 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1216 lines
		
	
	
	
		
			35 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (C) 2007-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
 | |
| 
 | |
| /* ======================================================================
 | |
|    Open Query Graph Computation Engine, based on a concept by Arjen Lentz
 | |
|    v3 implementation by Antony Curtis, Arjen Lentz, Andrew McDonnell
 | |
|    For more information, documentation, support, enhancement engineering,
 | |
|    see http://openquery.com/graph or contact graph@openquery.com
 | |
|    ======================================================================
 | |
| */
 | |
| 
 | |
| #include <string.h>
 | |
| #include <cstdlib>
 | |
| 
 | |
| #include "graphcore-graph.h"
 | |
| 
 | |
| #include <set>
 | |
| #include <stack>
 | |
| 
 | |
| #include <boost/property_map/property_map.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"
 | |
| 
 | |
| #include <boost/unordered_map.hpp>
 | |
| #include <boost/version.hpp>
 | |
| 
 | |
| using namespace open_query;
 | |
| using namespace boost;
 | |
| 
 | |
| static const row empty_row = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
 | |
| 
 | |
| extern "C" const char* const oqgraph_boost_version= BOOST_LIB_VERSION;
 | |
| 
 | |
| namespace open_query
 | |
| {
 | |
| 
 | |
|   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),
 | |
|         m_edge(), m_weight(0)
 | |
|     {
 | |
|       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;
 | |
| 
 | |
|     optional<Vertex> find_vertex(VertexID id) const;
 | |
|     optional<Edge> find_edge(Vertex, Vertex) const;
 | |
| 
 | |
|     inline oqgraph_share(
 | |
|         TABLE* table,
 | |
|         Field* origid,
 | |
|         Field* destid,
 | |
|         Field* weight) throw()
 | |
|       : g(table, origid, destid, weight)
 | |
|     { }
 | |
|     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&) override;
 | |
|     int fetch_row(const row &, row&, const reference&) override;
 | |
| 
 | |
|     void current(reference& ref) const override
 | |
|     {
 | |
|       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&) override;
 | |
|     int fetch_row(const row &, row&, const reference&) override;
 | |
| 
 | |
|     void current(reference& ref) const override
 | |
|     {
 | |
|       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&) override;
 | |
|     int fetch_row(const row &, row&, const reference&) override;
 | |
| 
 | |
|     void current(reference& ref) const override
 | |
|     {
 | |
|       ref= last;
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   template <typename P, typename D>
 | |
|   struct GRAPHCORE_INTERNAL oqgraph_visit_leaves
 | |
|     : public base_visitor< oqgraph_visit_leaves<P,D> >
 | |
|   {
 | |
|     typedef on_finish_vertex event_filter;
 | |
| 
 | |
|     oqgraph_visit_leaves(const P& p, const D& 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)
 | |
|     {
 | |
|       typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
 | |
|       boost::tuples::tie(ei, ei_end) = out_edges(u, g);
 | |
|       if (ei == ei_end)
 | |
|       {
 | |
|         m_cursor.results.push(reference(++seq, u, m_d[ u ]));
 | |
|       }
 | |
|     }
 | |
|   private:
 | |
|     int seq;
 | |
|     stack_cursor &m_cursor;
 | |
|     P m_p;
 | |
|     D m_d;
 | |
|   };
 | |
| 
 | |
|   template <typename P, typename D>
 | |
|   oqgraph_visit_leaves<P,D>
 | |
|     make_oqgraph_visit_leaves(const P& p, const D& d, stack_cursor *cursor)
 | |
|   { return oqgraph_visit_leaves<P,D>(p, d, cursor); }
 | |
| 
 | |
| 
 | |
|   template <typename P, typename D>
 | |
|   struct GRAPHCORE_INTERNAL oqgraph_visit_dist
 | |
|     : public base_visitor< oqgraph_visit_dist<P,D> >
 | |
|   {
 | |
|     typedef on_finish_vertex event_filter;
 | |
| 
 | |
|     oqgraph_visit_dist(const P& p, const D& 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[ u ]));
 | |
|     }
 | |
|   private:
 | |
|     int seq;
 | |
|     stack_cursor &m_cursor;
 | |
|     P m_p;
 | |
|     D m_d;
 | |
|   };
 | |
| 
 | |
|   template <typename P, typename D>
 | |
|   oqgraph_visit_dist<P,D>
 | |
|     make_oqgraph_visit_dist(const P& p, const D& d, stack_cursor *cursor)
 | |
|   { return oqgraph_visit_dist<P,D>(p, d, cursor); }
 | |
| 
 | |
| 
 | |
|   template<bool record_weight, typename goal_filter, typename P>
 | |
|   struct GRAPHCORE_INTERNAL oqgraph_goal
 | |
|     : public base_visitor<oqgraph_goal<record_weight,goal_filter,P> >
 | |
|   {
 | |
|     typedef goal_filter event_filter;
 | |
| 
 | |
|     oqgraph_goal(const Vertex& goal, const P& 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;
 | |
| 
 | |
|         for (Vertex q, v= u;; v = q, seq++)
 | |
|           if ((q= m_p[ v ]) == v)
 | |
|             break;
 | |
| 
 | |
|         for (Vertex v= u;; u= v)
 | |
|         {
 | |
|           optional<Edge> edge;
 | |
|           optional<EdgeWeight> weight;
 | |
|           v= m_p[ u ];
 | |
|           if (record_weight && u != v)
 | |
|           {
 | |
|             typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
 | |
|             for (boost::tuples::tie(ei, ei_end)= out_edges(v, g); ei != ei_end; ++ei)
 | |
|             {
 | |
|               if (target(*ei, g) == u)
 | |
|               {
 | |
|                 edge= *ei;
 | |
|                 weight= get(boost::edge_weight, 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;
 | |
|     P m_p;
 | |
|   };
 | |
| 
 | |
|   template<bool record_weight, typename goal_filter, typename P>
 | |
|   oqgraph_goal<record_weight, goal_filter, P>
 | |
|     make_oqgraph_goal(const Vertex& goal, const P& p, stack_cursor *cursor)
 | |
|   { return oqgraph_goal<record_weight, goal_filter, P>(goal, p, cursor); }
 | |
| 
 | |
| }
 | |
| 
 | |
| namespace open_query
 | |
| {
 | |
|   inline oqgraph::oqgraph(oqgraph_share *arg) throw()
 | |
|     : share(arg), cursor(0), lastRetainedLatch(NULL)
 | |
|   { }
 | |
| 
 | |
|   inline oqgraph::~oqgraph() throw()
 | |
|   {
 | |
|     std::free(lastRetainedLatch);
 | |
|     delete cursor;
 | |
|   }
 | |
| 
 | |
|   unsigned oqgraph::edges_count() const throw()
 | |
|   {
 | |
|     return num_edges(share->g);
 | |
|   }
 | |
| 
 | |
|   unsigned oqgraph::vertices_count() const throw()
 | |
|   {
 | |
|     return num_vertices(share->g);
 | |
|   }
 | |
| 
 | |
|   THD* oqgraph::get_thd() { return share->g.get_table_thd(); }
 | |
|   void oqgraph::set_thd(THD* thd) { share->g.set_table_thd(thd); }
 | |
| 
 | |
|   oqgraph* oqgraph::create(oqgraph_share *share) throw()
 | |
|   {
 | |
|     assert(share != NULL);
 | |
|     return new (std::nothrow) oqgraph(share);
 | |
|   }
 | |
| 
 | |
|   oqgraph_share* oqgraph::create(
 | |
|       TABLE* table,
 | |
|       Field* origid,
 | |
|       Field* destid,
 | |
|       Field* weight) throw()
 | |
|   {
 | |
|     return new (std::nothrow) oqgraph_share(
 | |
|         table, origid, destid, weight);
 | |
|   }
 | |
| 
 | |
|   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= std::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= std::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 oqgraph3::find_vertex(id, g);
 | |
|   }
 | |
| 
 | |
| #if 0
 | |
|   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 ? get(boost::vertex_index, share->g, *orig) != *orig_id : 0;
 | |
|     bool dest_neq= dest_id ? get(boost::vertex_index, share->g, *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;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   // THIS IS UGLY - refactor later
 | |
|   // Update the retained latch string value, for later retrieval by
 | |
|   // fetch_row() as a workaround for making sure we return the correct
 | |
|   // string to match the latch='' clause
 | |
|   // (This is a hack for mariadb mysql compatibility)
 | |
|   // IT SHOULD ONLY BE CALLED IMMEIDATELY BEFORE search)(
 | |
|   void oqgraph::retainLatchFieldValue(const char *retainedLatch) 
 | |
|   {
 | |
|     // attempting to use std::string broke lots of stuff
 | |
|     // Probably more efficient to use mysql String class, FIXME later
 | |
|     if (lastRetainedLatch) { std::free(lastRetainedLatch); lastRetainedLatch = NULL; }
 | |
|     if (retainedLatch) { lastRetainedLatch = strdup(retainedLatch); }
 | |
|   }
 | |
| 
 | |
|   // Because otherwise things can happen and we havent freed a resource since the end of the last query...
 | |
|   void oqgraph::release_cursor() throw() {
 | |
|     if (share->g._cursor) {
 | |
|       // Make sure refs all freed before deleting share->g._cursor
 | |
|       share->g._rnd_cursor = 0;      
 | |
|       delete cursor; cursor = 0;
 | |
|       delete share->g._cursor;
 | |
|       share->g._cursor = NULL;
 | |
|     }
 | |
|     row_info= empty_row;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   int oqgraph::search(int *latch, VertexID *orig_id, VertexID *dest_id) throw()
 | |
|   {
 | |
|       optional<Vertex> orig, dest;
 | |
|       int op= 0, seq= 0;
 | |
| 
 | |
|       delete cursor; cursor= 0;
 | |
|       row_info= empty_row;
 | |
|       if ((row_info.latch_indicator= latch)) {
 | |
|         op= ALGORITHM & (row_info.latch= *latch);
 | |
|         row_info.latchStringValue = lastRetainedLatch;
 | |
|         row_info.latchStringValueLen = strlen(lastRetainedLatch);
 | |
|       }
 | |
|       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 (boost::tuples::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,
 | |
|                     get(boost::edge_weight, share->g, *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 (boost::tuples::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,
 | |
|                     get(boost::edge_weight, share->g, *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)
 | |
|         {
 | |
|           boost::unordered_map<Vertex, Vertex> p;
 | |
|           boost::unordered_map<Vertex, EdgeWeight> d;
 | |
|           p[ *orig ]= *orig;
 | |
|           d[ *orig ] = EdgeWeight();
 | |
|           try
 | |
|           {
 | |
|             dijkstra_shortest_paths_no_init(share->g, *orig,
 | |
|                 make_lazy_property_map(p, identity_initializer<Vertex>()),
 | |
|                 make_lazy_property_map(d, value_initializer<EdgeWeight>(
 | |
|                     (std::numeric_limits<EdgeWeight>::max)())),
 | |
|                 get(edge_weight, share->g),
 | |
|                 get(vertex_index, share->g),
 | |
|                 std::less<EdgeWeight>(),
 | |
|                 closed_plus<EdgeWeight>(),
 | |
|                 EdgeWeight(),
 | |
|                 make_dijkstra_visitor(
 | |
|                     make_oqgraph_goal<true, on_finish_vertex>(
 | |
|                         *dest,
 | |
|                         boost::make_assoc_property_map(p),
 | |
|                         static_cast<stack_cursor*>(cursor)
 | |
|                     )
 | |
|                 ),
 | |
|                 make_two_bit_judy_map(get(vertex_index, share->g)));
 | |
|           }
 | |
|           catch (...)
 | |
|           { /* printf("found\n"); */ }
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|       case BREADTH_FIRST | HAVE_ORIG | HAVE_DEST:
 | |
|         if ((cursor= new (std::nothrow) stack_cursor(share)) && orig && dest)
 | |
|         {
 | |
|           boost::unordered_map<Vertex, Vertex> p;
 | |
|           boost::queue<Vertex> Q;
 | |
|           p[ *orig ]= *orig;
 | |
|           try
 | |
|           {
 | |
|             breadth_first_visit(share->g, *orig, Q,
 | |
|                 make_bfs_visitor(
 | |
|                     std::make_pair(
 | |
|                         record_predecessors(
 | |
|                             boost::make_assoc_property_map(p),
 | |
|                             on_tree_edge()
 | |
|                         ),
 | |
|                         make_oqgraph_goal<false, on_discover_vertex>(
 | |
|                             *dest, boost::make_assoc_property_map(p),
 | |
|                             static_cast<stack_cursor*>(cursor)
 | |
|                         )
 | |
|                     )
 | |
|                 ),
 | |
|                 make_two_bit_judy_map(get(vertex_index, share->g)));
 | |
|           }
 | |
|           catch (...)
 | |
|           { /* printf("found\n"); */ }
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|       case DIJKSTRAS | HAVE_ORIG:
 | |
|       case BREADTH_FIRST | HAVE_ORIG:
 | |
|       case LEAVES | HAVE_ORIG:
 | |
|         if ((cursor= new (std::nothrow) stack_cursor(share)) && (orig || dest))
 | |
|         {
 | |
|           boost::unordered_map<Vertex, Vertex> p;
 | |
|           boost::unordered_map<Vertex, EdgeWeight> d;
 | |
|           boost::queue<Vertex> Q;
 | |
|           p[ *orig ]= *orig;
 | |
|           d[ *orig ] = EdgeWeight();
 | |
|           switch (ALGORITHM & op)
 | |
|           {
 | |
|           case DIJKSTRAS:
 | |
|             dijkstra_shortest_paths_no_init(share->g, *orig,
 | |
|                 make_lazy_property_map(p, identity_initializer<Vertex>()),
 | |
|                 make_lazy_property_map(d, value_initializer<EdgeWeight>(
 | |
|                     (std::numeric_limits<EdgeWeight>::max)())),
 | |
|                 get(edge_weight, share->g),
 | |
|                 get(vertex_index, share->g),
 | |
|                 std::less<EdgeWeight>(),
 | |
|                 closed_plus<EdgeWeight>(),
 | |
|                 EdgeWeight(),
 | |
|                 make_dijkstra_visitor(
 | |
|                     make_oqgraph_visit_dist(
 | |
|                         boost::make_assoc_property_map(p), 
 | |
|                         boost::make_assoc_property_map(d),
 | |
|                         static_cast<stack_cursor*>(cursor)
 | |
|                     )
 | |
|                 ),
 | |
|                 make_two_bit_judy_map(get(vertex_index, share->g)));
 | |
|             break;
 | |
|           case BREADTH_FIRST:
 | |
|             breadth_first_visit(share->g, *orig, Q,
 | |
|                 make_bfs_visitor(
 | |
|                     std::make_pair(
 | |
|                         record_predecessors(
 | |
|                             boost::make_assoc_property_map(p),
 | |
|                             on_tree_edge()
 | |
|                         ),
 | |
|                     std::make_pair(
 | |
|                         record_distances(
 | |
|                             boost::make_assoc_property_map(d),
 | |
|                             on_tree_edge()
 | |
|                         ),
 | |
|                         make_oqgraph_visit_dist(
 | |
|                             boost::make_assoc_property_map(p),
 | |
|                             boost::make_assoc_property_map(d),
 | |
|                             static_cast<stack_cursor*>(cursor)
 | |
|                         )
 | |
|                     ))
 | |
|                 ),
 | |
|                 make_two_bit_judy_map(get(vertex_index, share->g)));
 | |
|             break;
 | |
|           case LEAVES:
 | |
|             breadth_first_visit(share->g, *orig, Q,
 | |
|                 make_bfs_visitor(
 | |
|                     std::make_pair(
 | |
|                         record_predecessors(
 | |
|                             boost::make_assoc_property_map(p),
 | |
|                             on_tree_edge()
 | |
|                         ),
 | |
|                     std::make_pair(
 | |
|                         record_distances(
 | |
|                             boost::make_assoc_property_map(d),
 | |
|                             on_tree_edge()
 | |
|                         ),
 | |
|                         make_oqgraph_visit_leaves(
 | |
|                             boost::make_assoc_property_map(p),
 | |
|                             boost::make_assoc_property_map(d),
 | |
|                             static_cast<stack_cursor*>(cursor)
 | |
|                         )
 | |
|                     ))
 | |
|                 ),
 | |
|                 make_two_bit_judy_map(get(vertex_index, share->g)));
 | |
|             break;
 | |
|           default:
 | |
|             abort();
 | |
|           }
 | |
|         }
 | |
|         break;
 | |
|       case BREADTH_FIRST | HAVE_DEST:
 | |
|       case DIJKSTRAS | HAVE_DEST:
 | |
|       case LEAVES | HAVE_DEST:
 | |
|         if ((cursor= new (std::nothrow) stack_cursor(share)) && (orig || dest))
 | |
|         {
 | |
|           boost::unordered_map<Vertex, Vertex> p;
 | |
|           boost::unordered_map<Vertex, EdgeWeight> d;
 | |
|           boost::queue<Vertex> Q;
 | |
|           const reverse_graph<Graph> r(share->g);
 | |
|           p[ *dest ]= *dest;
 | |
|           d[ *dest ] = EdgeWeight();
 | |
|           switch (ALGORITHM & op)
 | |
|           {
 | |
|           case DIJKSTRAS:
 | |
|             dijkstra_shortest_paths_no_init(r, *dest,
 | |
|                 make_lazy_property_map(p, identity_initializer<Vertex>()),
 | |
|                 make_lazy_property_map(d, value_initializer<EdgeWeight>(
 | |
|                     (std::numeric_limits<EdgeWeight>::max)())),
 | |
|                 get(edge_weight, r),
 | |
|                 get(vertex_index, r),
 | |
|                 std::less<EdgeWeight>(),
 | |
|                 closed_plus<EdgeWeight>(),
 | |
|                 EdgeWeight(),
 | |
|                 make_dijkstra_visitor(
 | |
|                         make_oqgraph_visit_dist(
 | |
|                             boost::make_assoc_property_map(p),
 | |
|                             boost::make_assoc_property_map(d),
 | |
|                             static_cast<stack_cursor*>(cursor)
 | |
|                         )
 | |
|                 ),
 | |
|                 make_two_bit_judy_map(get(vertex_index, r)));
 | |
|             break;
 | |
|           case BREADTH_FIRST:
 | |
|             breadth_first_visit(r, *dest, Q,
 | |
|                 make_bfs_visitor(
 | |
|                     std::make_pair(
 | |
|                         record_predecessors(
 | |
|                             boost::make_assoc_property_map(p),
 | |
|                             on_tree_edge()
 | |
|                         ),
 | |
|                     std::make_pair(
 | |
|                         record_distances(
 | |
|                             boost::make_assoc_property_map(d),
 | |
|                             on_tree_edge()
 | |
|                         ),
 | |
|                         make_oqgraph_visit_dist(
 | |
|                             boost::make_assoc_property_map(p),
 | |
|                             boost::make_assoc_property_map(d),
 | |
|                             static_cast<stack_cursor*>(cursor)
 | |
|                         )
 | |
|                     ))
 | |
|                 ),
 | |
|                 make_two_bit_judy_map(get(vertex_index, r)));
 | |
|             break;
 | |
|           case LEAVES:
 | |
|             breadth_first_visit(r, *dest, Q,
 | |
|                 make_bfs_visitor(
 | |
|                     std::make_pair(
 | |
|                         record_predecessors(
 | |
|                             boost::make_assoc_property_map(p),
 | |
|                             on_tree_edge()
 | |
|                         ),
 | |
|                     std::make_pair(
 | |
|                         record_distances(
 | |
|                             boost::make_assoc_property_map(d),
 | |
|                             on_tree_edge()
 | |
|                         ),
 | |
|                         make_oqgraph_visit_leaves(
 | |
|                             boost::make_assoc_property_map(p),
 | |
|                             boost::make_assoc_property_map(d),
 | |
|                             static_cast<stack_cursor*>(cursor)
 | |
|                         )
 | |
|                     ))
 | |
|                 ),
 | |
|                 make_two_bit_judy_map(get(vertex_index, r)));
 | |
|             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
 | |
|       // Beware: internally this eventually causes a swap by intrusive_ptr, so ref must be initialised to sane on all cases
 | |
|       ref = reference(); 
 | |
|   }
 | |
| 
 | |
|   void oqgraph::init_row_ref(void *ref_ptr) throw()
 | |
|   {
 | |
|     // Placement new will cause a constructor to be called avoiding the assignment operator of intrusive_ptr
 | |
|     // This doesnt allocate any memory, assumes ref_ptr is the correct size(!)
 | |
|     new (ref_ptr) reference(); 
 | |
|   }
 | |
| 
 | |
|   int oqgraph::random(bool scan) throw()
 | |
|   {
 | |
|     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 (last.vertex())
 | |
|   {
 | |
|     optional<int> seq;
 | |
|     optional<EdgeWeight> w;
 | |
|     optional<Vertex> v;
 | |
|     result= row_info;
 | |
|     if ((result.seq_indicator= static_cast<bool>(seq= last.sequence())))
 | |
|       result.seq= *seq;
 | |
|     if ((result.link_indicator= static_cast<bool>(v= last.vertex())))
 | |
|       result.link= get(boost::vertex_index, share->g, *v);
 | |
|     if ((result.weight_indicator= static_cast<bool>(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= get(boost::vertex_index, share->g, *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+= get(boost::edge_weight, share->g, *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+= get(boost::edge_weight, share->g, *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;
 | |
|   tie(it, end)= edges(share->g);
 | |
|   it+= position;
 | |
|   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;
 | |
| 
 | |
|     oqgraph3::vertex_id orig = get(boost::vertex_index, share->g, source( *edge, share->g ) );
 | |
|     oqgraph3::vertex_id dest = get(boost::vertex_index, share->g, target( *edge, share->g ) );
 | |
| 
 | |
|     // bug 796647c - may be symptomatic of a bigger problem with representation
 | |
|     // but origid and destid can be -1 indicating no such record, NULL? but oqgraph3::vertex_id
 | |
|     // seems to resolve to VertexID (unsigned) in row
 | |
|     // in any case we should check for errors (-1) in origid... because all edges have at least one vertex by definition
 | |
|     if (orig == (oqgraph3::vertex_id)-1 && dest == (oqgraph3::vertex_id)-1) {
 | |
|       // Select * from graph; -- when backing store is empty (bug MDEV-5891)
 | |
|       return oqgraph::NO_MORE_DATA;
 | |
|     }
 | |
|     //    assert( ! ((size_t)orig == (size_t)-1 && (size_t)dest == (size_t)-1)); 
 | |
|     // indicates we havent handle a HA_ERR_RECORD_DELETED somewhere
 | |
| 
 | |
|     result.orig= orig;
 | |
|     result.dest= dest;
 | |
|     result.weight= get(boost::edge_weight, share->g, *edge);
 | |
|     return oqgraph::OK;
 | |
|   }
 | |
|   return oqgraph::NO_MORE_DATA;
 | |
| }
 | |
| 
 | |
| namespace boost {
 | |
|   GRAPHCORE_INTERNAL void throw_exception(std::exception const&)
 | |
|   {
 | |
|     abort();
 | |
|   }
 | |
| }
 | 
