Merge lp:~posulliv/oqgraph/drizzle-port into lp:oqgraph

Proposed by Padraig O'Sullivan
Status: Needs review
Proposed branch: lp:~posulliv/oqgraph/drizzle-port
Merge into: lp:oqgraph
Diff against target: 3255 lines
18 files modified
oqgraph/README (+15/-0)
oqgraph/graphcore-graph.h (+56/-0)
oqgraph/graphcore-types.h (+36/-0)
oqgraph/graphcore.cc (+1034/-0)
oqgraph/graphcore.h (+116/-0)
oqgraph/graphstore.c (+356/-0)
oqgraph/graphstore.h (+90/-0)
oqgraph/ha_oqgraph.cc (+884/-0)
oqgraph/ha_oqgraph.h (+118/-0)
oqgraph/open_tables.cc (+91/-0)
oqgraph/open_tables.h (+93/-0)
oqgraph/oqgraph_config.h.in (+73/-0)
oqgraph/oqgraph_probes.d (+19/-0)
oqgraph/oqgraph_probes.h (+45/-0)
oqgraph/plugin.am (+67/-0)
oqgraph/plugin.ini (+9/-0)
oqgraph/tests/r/basic.result (+33/-0)
oqgraph/tests/t/basic.test (+25/-0)
To merge this branch: bzr merge lp:~posulliv/oqgraph/drizzle-port
Reviewer Review Type Date Requested Status
Antony T Curtis pending/comment Abstain
Arjen Lentz highlevel review Abstain
Review via email: mp+13910@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Padraig O'Sullivan (posulliv) wrote :

Hi!

I wanted to mess around with this engine and since I work mostly with drizzle, I ported it to drizzle. I thought I would submit the work I did to port the engine in case it is of any use to you guys.

I created a subdir named oqgraph that can simply be dropped in to the drizzle plugin directory. I also created a simple test suite for the engine that can be added under tests/suite in the drizzle tree.

I have a branch in drizzle for this work also:

lp:~posulliv/drizzle/oqgraph

If you check that branch out, you can just do the following:

$ ./config/autorun.sh && ./configure && make && make test

and it will automatically run the oqgraph test suite.

I removed the boost subdir for the drizzle port. For future work, I would need to make boost a compile time dependency for the plugin. I also need to investigate the usage of the bitmaps with this engine and make sure everything is ok here. Some weird assertion failures pop up with the read/write sets from time to time.

Anyway, feel free to use what I have done if you like. Let me know if it is of any use to you.

-Padraig

Revision history for this message
Arjen Lentz (arjen-lentz) wrote :

Hi Padraig

> I wanted to mess around with this engine and since I work mostly with drizzle,
> I ported it to drizzle. I thought I would submit the work I did to port the
> engine in case it is of any use to you guys.

He wow that was quick! Thanks.
Stewart was interested too but I guess you were faster, all the way to delivery ;-)

I'll let Antony decide on the code changes you made.

Dir structure wise, I think we need to do this differently, so we don't have the same file in multiple places (bzr supports symlinks).

Cheers,
Arjen.

review: Abstain (highlevel review)
Revision history for this message
Antony T Curtis (atcurtis) wrote :

> Hi Padraig
>
> > I wanted to mess around with this engine and since I work mostly with
> drizzle,
> > I ported it to drizzle. I thought I would submit the work I did to port the
> > engine in case it is of any use to you guys.
>
> He wow that was quick! Thanks.
> Stewart was interested too but I guess you were faster, all the way to
> delivery ;-)
>
> I'll let Antony decide on the code changes you made.

I need to get my Drizzle build back up to date and then I will examine this in detail.

> Dir structure wise, I think we need to do this differently, so we don't have
> the same file in multiple places (bzr supports symlinks).

I am thinking along the lines of having the Drizzle and MySQL build under the same "roof" but have the build selective upon which is present since the graphcore is pretty much independent of the database abstraction. So we'd have "configure --with-mysql=..." and/or "configure --with-drizzle=..."

Regards,
Antony.

review: Abstain (pending/comment)
Revision history for this message
Padraig O'Sullivan (posulliv) wrote :

> > I'll let Antony decide on the code changes you made.
>
> I need to get my Drizzle build back up to date and then I will examine this in
> detail.
>
> > Dir structure wise, I think we need to do this differently, so we don't have
> > the same file in multiple places (bzr supports symlinks).
>
> I am thinking along the lines of having the Drizzle and MySQL build under the
> same "roof" but have the build selective upon which is present since the
> graphcore is pretty much independent of the database abstraction. So we'd have
> "configure --with-mysql=..." and/or "configure --with-drizzle=..."

That makes perfect sense. I wanted to do this but I am not really familiar with MySQL internals and it seems that drizzle has diverged quite a bit at the storage engine layer so I wasn't able to keep things in the same place and utilize conditional compilation. As you said it is just the handler (or Cursor in drizzle) that needs to change for the engine.

Anyway, I hope its useful to see the changes that were needed for porting it. If you guys need any help when you get around to doing porting the engine to drizzle, I'd be happy to help if you want.

-Padraig

>
> Regards,
> Antony.

Unmerged revisions

12. By Padraig O'Sullivan

Updated the create table method to verify that created tables adhere to the
correct structure for the graph engine.

11. By Padraig O'Sullivan

Added test suite from drizzle.

10. By Padraig O'Sullivan

Added new class for tracking open tables in the engine. Removed the boost
libraries from the engine. We will make it a build time dependency instead.
If boost is not present then the engine will not be built.

9. By Padraig O'Sullivan

Various updates from debugging the engine on drizzle.

8. By Padraig O'Sullivan

Updated the handler class to conform to drizzle.

7. By Padraig O'Sullivan

Updated the build files again for drizzle.

6. By Padraig O'Sullivan

Porting the handler files to work with drizzle.

5. By Padraig O'Sullivan

Updated build file for drizzle.

4. By Padraig O'Sullivan

Added some build related files.

3. By Padraig O'Sullivan

Initial work on porting the OQGRAPH engine to drizzle.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'oqgraph'
2=== added file 'oqgraph/README'
3--- oqgraph/README 1970-01-01 00:00:00 +0000
4+++ oqgraph/README 2009-10-25 07:55:23 +0000
5@@ -0,0 +1,15 @@
6+======================================================================
7+Open Query Graph Computation Engine, based on a concept by Arjen Lentz
8+Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
9+Mk.II implementation by Antony Curtis & Arjen Lentz
10+
11+- Open Query original code licensed under GPLv2+
12+- MySQL 5.0 derived glue code licensed under GPLv2
13+- Boost library licensed under Boost Software License (GPL compatible)
14+
15+For more information, documentation, support, enhancement engineering,
16+and non-GPL licensing, see http://openquery.com/graph
17+or contact graph@openquery.com
18+
19+For packaged binaries, see http://ourdelta.org
20+======================================================================
21
22=== added file 'oqgraph/graphcore-graph.h'
23--- oqgraph/graphcore-graph.h 1970-01-01 00:00:00 +0000
24+++ oqgraph/graphcore-graph.h 2009-10-25 07:55:23 +0000
25@@ -0,0 +1,56 @@
26+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
27+
28+ This program is free software; you can redistribute it and/or modify
29+ it under the terms of the GNU General Public License as published by
30+ the Free Software Foundation; version 2 of the License, or
31+ (at your option) any later version.
32+
33+ This program is distributed in the hope that it will be useful,
34+ but WITHOUT ANY WARRANTY; without even the implied warranty of
35+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36+ GNU General Public License for more details.
37+
38+ You should have received a copy of the GNU General Public License
39+ along with this program; if not, write to the Free Software
40+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
41+
42+/* ======================================================================
43+ Open Query Graph Computation Engine, based on a concept by Arjen Lentz
44+ Mk.II implementation by Antony Curtis & Arjen Lentz
45+ For more information, documentation, support, enhancement engineering,
46+ and non-GPL licensing, see http://openquery.com/graph
47+ or contact graph@openquery.com
48+ For packaged binaries, see http://ourdelta.org
49+ ======================================================================
50+*/
51+
52+#ifndef oq_graphcore_graph_h_
53+#define oq_graphcore_graph_h_
54+
55+typedef struct {
56+ VertexID id;
57+} VertexInfo;
58+
59+typedef struct {
60+ EdgeWeight weight;
61+} EdgeInfo;
62+
63+typedef adjacency_list
64+<
65+ vecS,
66+ vecS,
67+ bidirectionalS,
68+ VertexInfo,
69+ EdgeInfo
70+> Graph;
71+
72+#define GRAPH_WEIGHTMAP(G) get(&EdgeInfo::weight, G)
73+typedef property_map<Graph, EdgeWeight EdgeInfo::*>::type weightmap_type;
74+
75+#define GRAPH_INDEXMAP(G) get(vertex_index, G)
76+typedef property_map<Graph, vertex_index_t>::type indexmap_type;
77+
78+#define GRAPH_IDMAP(G) get(&VertexInfo::id, G)
79+typedef property_map<Graph, VertexID VertexInfo::*>::type idmap_type;
80+
81+#endif
82
83=== added file 'oqgraph/graphcore-types.h'
84--- oqgraph/graphcore-types.h 1970-01-01 00:00:00 +0000
85+++ oqgraph/graphcore-types.h 2009-10-25 07:55:23 +0000
86@@ -0,0 +1,36 @@
87+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
88+
89+ This program is free software; you can redistribute it and/or modify
90+ it under the terms of the GNU General Public License as published by
91+ the Free Software Foundation; version 2 of the License, or
92+ (at your option) any later version.
93+
94+ This program is distributed in the hope that it will be useful,
95+ but WITHOUT ANY WARRANTY; without even the implied warranty of
96+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
97+ GNU General Public License for more details.
98+
99+ You should have received a copy of the GNU General Public License
100+ along with this program; if not, write to the Free Software
101+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
102+
103+/* ======================================================================
104+ Open Query Graph Computation Engine, based on a concept by Arjen Lentz
105+ Mk.II implementation by Antony Curtis & Arjen Lentz
106+ For more information, documentation, support, enhancement engineering,
107+ and non-GPL licensing, see http://openquery.com/graph
108+ or contact graph@openquery.com
109+ For packaged binaries, see http://ourdelta.org
110+ ======================================================================
111+*/
112+
113+#ifndef oq_graphcore_types_h_
114+#define oq_graphcore_types_h_
115+namespace open_query
116+{
117+
118+ typedef unsigned long long VertexID;
119+ typedef double EdgeWeight;
120+
121+}
122+#endif
123
124=== added file 'oqgraph/graphcore.cc'
125--- oqgraph/graphcore.cc 1970-01-01 00:00:00 +0000
126+++ oqgraph/graphcore.cc 2009-10-25 07:55:23 +0000
127@@ -0,0 +1,1034 @@
128+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
129+
130+ This program is free software; you can redistribute it and/or modify
131+ it under the terms of the GNU General Public License as published by
132+ the Free Software Foundation; version 2 of the License, or
133+ (at your option) any later version.
134+
135+ This program is distributed in the hope that it will be useful,
136+ but WITHOUT ANY WARRANTY; without even the implied warranty of
137+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
138+ GNU General Public License for more details.
139+
140+ You should have received a copy of the GNU General Public License
141+ along with this program; if not, write to the Free Software
142+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
143+
144+/* ======================================================================
145+ Open Query Graph Computation Engine, based on a concept by Arjen Lentz
146+ Mk.II implementation by Antony Curtis & Arjen Lentz
147+ For more information, documentation, support, enhancement engineering,
148+ and non-GPL licensing, see http://openquery.com/graph
149+ or contact graph@openquery.com
150+ For packaged binaries, see http://ourdelta.org
151+ ======================================================================
152+*/
153+
154+#include <strings.h>
155+
156+#define BOOST_ALL_NO_LIB 1
157+
158+#include <boost/config.hpp>
159+
160+#include <set>
161+#include <stack>
162+
163+#include <boost/property_map.hpp>
164+
165+#include <boost/graph/graph_concepts.hpp>
166+#include <boost/graph/graph_archetypes.hpp>
167+#include <boost/graph/adjacency_list.hpp>
168+#include <boost/graph/breadth_first_search.hpp>
169+#include <boost/graph/dijkstra_shortest_paths.hpp>
170+#include <boost/graph/iteration_macros.hpp>
171+#include <boost/graph/reverse_graph.hpp>
172+#include <boost/graph/graph_utility.hpp>
173+
174+#include "graphcore.h"
175+
176+using namespace open_query;
177+using namespace boost;
178+
179+enum vertex_id_t { vertex_id };
180+
181+static const row empty_row = { 0 };
182+
183+namespace boost
184+{
185+ BOOST_INSTALL_PROPERTY(vertex, id);
186+}
187+
188+namespace open_query {
189+
190+ #include "graphcore-graph.h"
191+
192+ typedef graph_traits<Graph>::vertex_descriptor Vertex;
193+ typedef graph_traits<Graph>::edge_descriptor Edge;
194+
195+ typedef std::list<std::pair<Vertex,optional<EdgeWeight> > > shortest_path_list;
196+ typedef shortest_path_list::iterator shortest_path_iterator;
197+
198+ template<typename ID, typename IDMap>
199+ class id_equals_t
200+ {
201+ public:
202+ id_equals_t(ID id, IDMap map)
203+ : m_id(id), m_map(map)
204+ { }
205+ template<typename V>
206+ bool operator()(V u) const
207+ {
208+ return m_map[u] == m_id;
209+ }
210+ private:
211+ ID m_id;
212+ IDMap m_map;
213+ };
214+
215+ template<typename ID, typename IDMap>
216+ inline id_equals_t<ID,IDMap>
217+ id_equals(ID id, IDMap idmap)
218+ {
219+ return id_equals_t<ID,IDMap>(id, idmap);
220+ }
221+
222+ template<typename T, typename Graph>
223+ class target_equals_t
224+ {
225+ public:
226+ target_equals_t(T target, Graph &g)
227+ : m_target(target), m_g(g)
228+ { }
229+ template<typename V>
230+ bool operator()(V u) const
231+ {
232+ return target(u, m_g) == m_target;
233+ }
234+ private:
235+ T m_target;
236+ Graph &m_g;
237+ };
238+
239+ template<typename T, typename Graph>
240+ inline target_equals_t<T,Graph>
241+ target_equals(T target, Graph &g)
242+ {
243+ return target_equals_t<T,Graph>(target, g);
244+ }
245+
246+ template<typename T, typename Graph>
247+ class source_equals_t
248+ {
249+ public:
250+ source_equals_t(T source, Graph &g)
251+ : m_source(source), m_g(g)
252+ { }
253+ template<typename V>
254+ bool operator()(V u) const
255+ {
256+ return source(u, m_g) == m_source;
257+ }
258+ private:
259+ T m_source;
260+ Graph &m_g;
261+ };
262+
263+ template<typename T, typename Graph>
264+ inline source_equals_t<T,Graph>
265+ source_equals(T source, Graph &g)
266+ {
267+ return source_equals_t<T,Graph>(source, g);
268+ }
269+
270+ struct reference
271+ {
272+ int m_flags;
273+ int m_sequence;
274+ Vertex m_vertex;
275+ Edge m_edge;
276+ EdgeWeight m_weight;
277+
278+ enum
279+ {
280+ HAVE_SEQUENCE = 1,
281+ HAVE_WEIGHT = 2,
282+ HAVE_EDGE = 4,
283+ };
284+
285+ inline reference()
286+ : m_flags(0), m_sequence(0),
287+ m_vertex(graph_traits<Graph>::null_vertex()),
288+ m_edge(), m_weight(0)
289+ { }
290+
291+ inline reference(int s, Edge e)
292+ : m_flags(HAVE_SEQUENCE | HAVE_EDGE), m_sequence(s),
293+ m_vertex(graph_traits<Graph>::null_vertex()),
294+ m_edge(e), m_weight(0)
295+ { }
296+
297+ inline reference(int s, Vertex v, const optional<Edge> &e,
298+ const optional<EdgeWeight> &w)
299+ : m_flags(HAVE_SEQUENCE | (w ? HAVE_WEIGHT : 0) | (e ? HAVE_EDGE : 0)),
300+ m_sequence(s), m_vertex(v)
301+ {
302+ if (w) m_weight= *w;
303+ if (e) m_edge= *e;
304+ }
305+
306+ inline reference(int s, Vertex v, Edge e, EdgeWeight w)
307+ : m_flags(HAVE_SEQUENCE | HAVE_WEIGHT | HAVE_EDGE),
308+ m_sequence(s), m_vertex(v), m_edge(e), m_weight(w)
309+ { }
310+
311+ inline reference(int s, Vertex v, EdgeWeight w)
312+ : m_flags(HAVE_SEQUENCE | HAVE_WEIGHT),
313+ m_sequence(s), m_vertex(v), m_edge(), m_weight(w)
314+ { }
315+
316+ inline reference(int s, Vertex v)
317+ : m_flags(HAVE_SEQUENCE), m_sequence(s), m_vertex(v), m_edge(),
318+ m_weight(0)
319+ { }
320+
321+ optional<int> sequence() const
322+ {
323+ if (m_flags & HAVE_SEQUENCE)
324+ {
325+ return m_sequence;
326+ }
327+ return optional<int>();
328+ }
329+
330+ optional<Vertex> vertex() const
331+ {
332+ if (m_vertex != graph_traits<Graph>::null_vertex())
333+ return m_vertex;
334+ return optional<Vertex>();
335+ }
336+
337+ optional<Edge> edge() const
338+ {
339+ if (m_flags & HAVE_EDGE)
340+ return m_edge;
341+ return optional<Edge>();
342+ };
343+
344+ optional<EdgeWeight> weight() const
345+ {
346+ if (m_flags & HAVE_WEIGHT)
347+ return m_weight;
348+ return optional<EdgeWeight>();
349+ }
350+ };
351+}
352+
353+namespace open_query {
354+ class GRAPHCORE_INTERNAL oqgraph_share
355+ {
356+ public:
357+ Graph g;
358+
359+ weightmap_type weightmap;
360+ idmap_type idmap;
361+ indexmap_type indexmap;
362+
363+ optional<Vertex> find_vertex(VertexID id) const;
364+ optional<Edge> find_edge(Vertex, Vertex) const;
365+
366+ inline oqgraph_share() throw()
367+ : g(),
368+ weightmap(GRAPH_WEIGHTMAP(g)),
369+ idmap(GRAPH_IDMAP(g)),
370+ indexmap(GRAPH_INDEXMAP(g))
371+ { }
372+ inline ~oqgraph_share()
373+ { }
374+ };
375+
376+ class GRAPHCORE_INTERNAL oqgraph_cursor
377+ {
378+ public:
379+ oqgraph_share *const share;
380+
381+ inline oqgraph_cursor(oqgraph_share *arg)
382+ : share(arg)
383+ { }
384+ virtual ~oqgraph_cursor()
385+ { }
386+
387+ virtual int fetch_row(const row &, row&) = 0;
388+ virtual int fetch_row(const row &, row&, const reference&) = 0;
389+ virtual void current(reference& ref) const = 0;
390+ };
391+}
392+
393+namespace open_query {
394+ class GRAPHCORE_INTERNAL stack_cursor : public oqgraph_cursor
395+ {
396+ private:
397+ optional<EdgeWeight> no_weight;
398+ public:
399+ int sequence;
400+ std::stack<reference> results;
401+ reference last;
402+
403+ inline stack_cursor(oqgraph_share *arg)
404+ : oqgraph_cursor(arg), no_weight(), sequence(0), results(), last()
405+ { }
406+
407+ int fetch_row(const row &, row&);
408+ int fetch_row(const row &, row&, const reference&);
409+
410+ void current(reference& ref) const
411+ {
412+ ref= last;
413+ }
414+ };
415+
416+ class GRAPHCORE_INTERNAL vertices_cursor : public oqgraph_cursor
417+ {
418+ typedef graph_traits<Graph>::vertex_iterator vertex_iterator;
419+
420+ size_t position;
421+ reference last;
422+ public:
423+ inline vertices_cursor(oqgraph_share *arg)
424+ : oqgraph_cursor(arg), position(0)
425+ { }
426+
427+ int fetch_row(const row &, row&);
428+ int fetch_row(const row &, row&, const reference&);
429+
430+ void current(reference& ref) const
431+ {
432+ ref= last;
433+ }
434+
435+ };
436+
437+ class GRAPHCORE_INTERNAL edges_cursor : public oqgraph_cursor
438+ {
439+ typedef graph_traits<Graph>::edge_iterator edge_iterator;
440+ typedef edge_iterator::difference_type edge_difference;
441+
442+ edge_difference position;
443+ reference last;
444+ public:
445+ inline edges_cursor(oqgraph_share *arg)
446+ : oqgraph_cursor(arg), position(0), last()
447+ { }
448+
449+ int fetch_row(const row &, row&);
450+ int fetch_row(const row &, row&, const reference&);
451+
452+ void current(reference& ref) const
453+ {
454+ ref= last;
455+ }
456+ };
457+
458+ struct GRAPHCORE_INTERNAL oqgraph_visit_dist
459+ : public base_visitor<oqgraph_visit_dist>
460+ {
461+ typedef on_finish_vertex event_filter;
462+
463+ oqgraph_visit_dist(std::vector<Vertex>::iterator p,
464+ std::vector<EdgeWeight>::iterator d,
465+ stack_cursor *cursor)
466+ : seq(0), m_cursor(*cursor), m_p(p), m_d(d)
467+ { assert(cursor); }
468+
469+ template<class T, class Graph>
470+ void operator()(T u, Graph &g)
471+ {
472+ m_cursor.results.push(reference(++seq, u, m_d[GRAPH_INDEXMAP(g)[u]]));
473+ }
474+ private:
475+ int seq;
476+ stack_cursor &m_cursor;
477+ std::vector<Vertex>::iterator m_p;
478+ std::vector<EdgeWeight>::iterator m_d;
479+ };
480+
481+ template<bool record_weight, typename goal_filter>
482+ struct GRAPHCORE_INTERNAL oqgraph_goal
483+ : public base_visitor<oqgraph_goal<record_weight,goal_filter> >
484+ {
485+ typedef goal_filter event_filter;
486+
487+ oqgraph_goal(Vertex goal, std::vector<Vertex>::iterator p,
488+ stack_cursor *cursor)
489+ : m_goal(goal), m_cursor(*cursor), m_p(p)
490+ { assert(cursor); }
491+
492+ template<class T, class Graph>
493+ void operator()(T u, Graph &g)
494+ {
495+ if (u == m_goal)
496+ {
497+ int seq= 0;
498+ indexmap_type indexmap= GRAPH_INDEXMAP(g);
499+
500+ for (Vertex q, v= u;; v = q, seq++)
501+ if ((q= m_p[ indexmap[v] ]) == v)
502+ break;
503+
504+ for (Vertex v= u;; u= v)
505+ {
506+ optional<Edge> edge;
507+ optional<EdgeWeight> weight;
508+ v= m_p[ indexmap[u] ];
509+ if (record_weight && u != v)
510+ {
511+ typename graph_traits<Graph>::out_edge_iterator ei, ei_end;
512+ for (tie(ei, ei_end)= out_edges(v, g); ei != ei_end; ++ei)
513+ {
514+ if (target(*ei, g) == u)
515+ {
516+ edge= *ei;
517+ weight= GRAPH_WEIGHTMAP(g)[*ei];
518+ break;
519+ }
520+ }
521+ }
522+ else if (u != v)
523+ weight= 1;
524+ m_cursor.results.push(reference(seq--, u, edge, weight));
525+ if (u == v)
526+ break;
527+ }
528+ throw this;
529+ }
530+ }
531+
532+ private:
533+ Vertex m_goal;
534+ stack_cursor &m_cursor;
535+ std::vector<Vertex>::iterator m_p;
536+ };
537+}
538+
539+namespace open_query
540+{
541+ inline oqgraph::oqgraph(oqgraph_share *arg) throw()
542+ : share(arg), cursor(0)
543+ { }
544+
545+ inline oqgraph::~oqgraph() throw()
546+ {
547+ delete cursor;
548+ }
549+
550+ unsigned oqgraph::edges_count() const throw()
551+ {
552+ return num_edges(share->g);
553+ }
554+
555+ unsigned oqgraph::vertices_count() const throw()
556+ {
557+ return num_vertices(share->g);
558+ }
559+
560+ oqgraph* oqgraph::create(oqgraph_share *share) throw()
561+ {
562+ assert(share != NULL);
563+ return new oqgraph(share);
564+ }
565+
566+ oqgraph_share* oqgraph::create() throw()
567+ {
568+ return new oqgraph_share();
569+ }
570+
571+ optional<Edge>
572+ oqgraph_share::find_edge(Vertex orig, Vertex dest) const
573+ {
574+ if (in_degree(dest, g) >= out_degree(orig, g))
575+ {
576+ graph_traits<Graph>::out_edge_iterator ei, ei_end;
577+ tie(ei, ei_end)= out_edges(orig, g);
578+ if ((ei= find_if(ei, ei_end, target_equals(dest, g))) != ei_end)
579+ return *ei;
580+ }
581+ else
582+ {
583+ graph_traits<Graph>::in_edge_iterator ei, ei_end;
584+ tie(ei, ei_end)= in_edges(dest, g);
585+ if ((ei= find_if(ei, ei_end, source_equals(orig, g))) != ei_end)
586+ return *ei;
587+ }
588+ return optional<Edge>();
589+ }
590+
591+ optional<Vertex>
592+ oqgraph_share::find_vertex(VertexID id) const
593+ {
594+ optional<Vertex> result;
595+ graph_traits<Graph>::vertex_iterator vi, viend;
596+
597+ tie(vi, viend)= vertices(g);
598+ if ((vi= std::find_if(vi, viend, id_equals(id, idmap))) != viend)
599+ result= *vi;
600+ return result;
601+ }
602+
603+ int oqgraph::delete_all() throw()
604+ {
605+ share->g.clear();
606+ return 0;
607+ }
608+
609+ int oqgraph::insert_edge(
610+ VertexID orig_id, VertexID dest_id, EdgeWeight weight, bool replace) throw()
611+ {
612+ optional<Vertex> orig, dest;
613+ optional<Edge> edge;
614+ bool inserted= 0;
615+
616+ if (weight < 0)
617+ return INVALID_WEIGHT;
618+ if (!(orig= share->find_vertex(orig_id)))
619+ {
620+ orig= add_vertex(share->g);
621+ if (orig == graph_traits<Graph>::null_vertex())
622+ return CANNOT_ADD_VERTEX;
623+ share->idmap[*orig]= orig_id;
624+ }
625+ if (!(dest= share->find_vertex(dest_id)))
626+ {
627+ dest= add_vertex(share->g);
628+ if (dest == graph_traits<Graph>::null_vertex())
629+ return CANNOT_ADD_VERTEX;
630+ share->idmap[*dest]= dest_id;
631+ }
632+ if (!(edge= share->find_edge(*orig, *dest)))
633+ {
634+ tie(edge, inserted)= add_edge(*orig, *dest, share->g);
635+ if (!inserted)
636+ return CANNOT_ADD_EDGE;
637+ }
638+ else
639+ {
640+ if (!replace)
641+ return DUPLICATE_EDGE;
642+ }
643+ share->weightmap[*edge]= weight;
644+ return OK;
645+ }
646+
647+ int oqgraph::delete_edge(current_row_st) throw()
648+ {
649+ reference ref;
650+ if (cursor)
651+ return EDGE_NOT_FOUND;
652+ cursor->current(ref);
653+ optional<Edge> edge;
654+ if (!(edge= ref.edge()))
655+ return EDGE_NOT_FOUND;
656+ Vertex orig= source(*edge, share->g);
657+ Vertex dest= target(*edge, share->g);
658+ remove_edge(*edge, share->g);
659+ if (!degree(orig, share->g))
660+ remove_vertex(orig, share->g);
661+ if (!degree(dest, share->g))
662+ remove_vertex(dest, share->g);
663+ return OK;
664+ }
665+
666+ int oqgraph::modify_edge(current_row_st,
667+ VertexID *orig_id, VertexID *dest_id, EdgeWeight *weight,
668+ bool replace) throw()
669+ {
670+ if (!cursor)
671+ return EDGE_NOT_FOUND;
672+ reference ref;
673+ cursor->current(ref);
674+ optional<Edge> edge;
675+ if (!(edge= ref.edge()))
676+ return EDGE_NOT_FOUND;
677+ if (weight && *weight < 0)
678+ return INVALID_WEIGHT;
679+
680+ optional<Vertex> orig= source(*edge, share->g),
681+ dest= target(*edge, share->g);
682+
683+ bool orig_neq= orig_id ? share->idmap[*orig] != *orig_id : 0;
684+ bool dest_neq= dest_id ? share->idmap[*dest] != *dest_id : 0;
685+ if (orig_neq || dest_neq)
686+ {
687+ optional<Edge> new_edge;
688+ if (orig_neq && !(orig= share->find_vertex(*orig_id)))
689+ {
690+ orig= add_vertex(share->g);
691+ if (orig == graph_traits<Graph>::null_vertex())
692+ return CANNOT_ADD_VERTEX;
693+ share->idmap[*orig]= *orig_id;
694+ }
695+ if (dest_neq && !(dest= share->find_vertex(*dest_id)))
696+ {
697+ dest= add_vertex(share->g);
698+ if (dest == graph_traits<Graph>::null_vertex())
699+ return CANNOT_ADD_VERTEX;
700+ share->idmap[*dest]= *dest_id;
701+ }
702+ if (!(new_edge= share->find_edge(*orig, *dest)))
703+ {
704+ bool inserted;
705+ tie(new_edge, inserted)= add_edge(*orig, *dest, share->g);
706+ if (!inserted)
707+ return CANNOT_ADD_EDGE;
708+ }
709+ else
710+ {
711+ if (!replace)
712+ return DUPLICATE_EDGE;
713+ }
714+ share->weightmap[*new_edge]= share->weightmap[*edge];
715+ remove_edge(*edge, share->g);
716+ edge= new_edge;
717+ }
718+ if (weight)
719+ share->weightmap[*edge]= *weight;
720+ return OK;
721+ }
722+
723+ int oqgraph::modify_edge(
724+ VertexID orig_id, VertexID dest_id, EdgeWeight weight) throw()
725+ {
726+ optional<Vertex> orig, dest;
727+ optional<Edge> edge;
728+
729+ if (weight < 0)
730+ return INVALID_WEIGHT;
731+ if (!(orig= share->find_vertex(orig_id)))
732+ return EDGE_NOT_FOUND;
733+ if (!(dest= share->find_vertex(dest_id)))
734+ return EDGE_NOT_FOUND;
735+ if (!(edge= share->find_edge(*orig, *dest)))
736+ return EDGE_NOT_FOUND;
737+ share->weightmap[*edge]= weight;
738+ return OK;
739+ }
740+
741+
742+ int oqgraph::delete_edge(VertexID orig_id, VertexID dest_id) throw()
743+ {
744+ optional<Vertex> orig, dest;
745+ optional<Edge> edge;
746+
747+ if (!(orig= share->find_vertex(orig_id)))
748+ return EDGE_NOT_FOUND;
749+ if (!(dest= share->find_vertex(dest_id)))
750+ return EDGE_NOT_FOUND;
751+ if (!(edge= share->find_edge(*orig, *dest)));
752+ return EDGE_NOT_FOUND;
753+ remove_edge(*edge, share->g);
754+ if (!degree(*orig, share->g))
755+ remove_vertex(*orig, share->g);
756+ if (!degree(*dest, share->g))
757+ remove_vertex(*dest, share->g);
758+ return OK;
759+ }
760+
761+
762+ int oqgraph::search(int *latch, VertexID *orig_id, VertexID *dest_id) throw()
763+ {
764+ optional<Vertex> orig, dest;
765+ int op= 0, seq= 0;
766+ enum {
767+ NO_SEARCH = 0,
768+ DIJKSTRAS = 1,
769+ BREADTH_FIRST = 2,
770+
771+ ALGORITHM = 0x0ffff,
772+ HAVE_ORIG = 0x10000,
773+ HAVE_DEST = 0x20000,
774+ };
775+
776+ delete cursor; cursor= 0;
777+ row_info= empty_row;
778+ if ((row_info.latch_indicator= latch))
779+ op= ALGORITHM & (row_info.latch= *latch);
780+ if ((row_info.orig_indicator= orig_id) && (op|= HAVE_ORIG))
781+ orig= share->find_vertex((row_info.orig= *orig_id));
782+ if ((row_info.dest_indicator= dest_id) && (op|= HAVE_DEST))
783+ dest= share->find_vertex((row_info.dest= *dest_id));
784+ //try
785+ //{
786+ switch (op)
787+ {
788+ case NO_SEARCH | HAVE_ORIG | HAVE_DEST:
789+ case NO_SEARCH | HAVE_ORIG:
790+ if ((cursor= new stack_cursor(share)) && orig)
791+ {
792+ graph_traits<Graph>::out_edge_iterator ei, ei_end;
793+ for (tie(ei, ei_end)= out_edges(*orig, share->g); ei != ei_end; ++ei)
794+ {
795+ Vertex v= target(*ei, share->g);
796+ static_cast<stack_cursor*>(cursor)->
797+ results.push(reference(++seq, v, *ei, share->weightmap[*ei]));
798+ }
799+ }
800+ /* fall through */
801+ case NO_SEARCH | HAVE_DEST:
802+ if ((op & HAVE_DEST) &&
803+ (cursor || (cursor= new stack_cursor(share))) && dest)
804+ {
805+ graph_traits<Graph>::in_edge_iterator ei, ei_end;
806+ for (tie(ei, ei_end)= in_edges(*dest, share->g); ei != ei_end; ++ei)
807+ {
808+ Vertex v= source(*ei, share->g);
809+ static_cast<stack_cursor*>(cursor)->
810+ results.push(reference(++seq, v, *ei, share->weightmap[*ei]));
811+ }
812+ }
813+ break;
814+
815+ case NO_SEARCH:
816+ cursor= new vertices_cursor(share);
817+ break;
818+
819+ case DIJKSTRAS | HAVE_ORIG | HAVE_DEST:
820+ if ((cursor= new stack_cursor(share)) && orig && dest)
821+ {
822+ std::vector<Vertex> p(num_vertices(share->g));
823+ std::vector<EdgeWeight> d(num_vertices(share->g));
824+ oqgraph_goal<true, on_finish_vertex>
825+ vis(*dest, p.begin(), static_cast<stack_cursor*>(cursor));
826+ p[share->indexmap[*orig]]= *orig;
827+ try
828+ {
829+ dijkstra_shortest_paths(share->g, *orig,
830+ weight_map(
831+ share->weightmap
832+ ).
833+ distance_map(
834+ make_iterator_property_map(d.begin(), share->indexmap)
835+ ).
836+ predecessor_map(
837+ make_iterator_property_map(p.begin(), share->indexmap)
838+ ).
839+ visitor(
840+ make_dijkstra_visitor(vis)
841+ )
842+ );
843+ }
844+ catch (...)
845+ { /* printf("found\n"); */ }
846+ }
847+ break;
848+
849+ case BREADTH_FIRST | HAVE_ORIG | HAVE_DEST:
850+ if ((cursor= new stack_cursor(share)) && orig && dest)
851+ {
852+ std::vector<Vertex> p(num_vertices(share->g));
853+ oqgraph_goal<false, on_discover_vertex>
854+ vis(*dest, p.begin(), static_cast<stack_cursor*>(cursor));
855+ p[share->indexmap[*orig]]= *orig;
856+ try
857+ {
858+ breadth_first_search(share->g, *orig,
859+ visitor(make_bfs_visitor(
860+ std::make_pair(
861+ record_predecessors(
862+ make_iterator_property_map(p.begin(), share->indexmap),
863+ on_tree_edge()
864+ ),
865+ vis)
866+ )
867+ )
868+ );
869+ }
870+ catch (...)
871+ { /* printf("found\n"); */ }
872+ }
873+ break;
874+
875+ case DIJKSTRAS | HAVE_ORIG:
876+ case BREADTH_FIRST | HAVE_ORIG:
877+ if ((cursor= new stack_cursor(share)) && (orig || dest))
878+ {
879+ std::vector<Vertex> p(num_vertices(share->g));
880+ std::vector<EdgeWeight> d(num_vertices(share->g));
881+ oqgraph_visit_dist vis(p.begin(), d.begin(),
882+ static_cast<stack_cursor*>(cursor));
883+ p[share->indexmap[*orig]]= *orig;
884+ switch (ALGORITHM & op)
885+ {
886+ case DIJKSTRAS:
887+ dijkstra_shortest_paths(share->g, *orig,
888+ weight_map(
889+ share->weightmap
890+ ).
891+ distance_map(
892+ make_iterator_property_map(d.begin(), share->indexmap)
893+ ).
894+ predecessor_map(
895+ make_iterator_property_map(p.begin(), share->indexmap)
896+ ).
897+ visitor(
898+ make_dijkstra_visitor(vis)
899+ )
900+ );
901+ break;
902+ case BREADTH_FIRST:
903+ breadth_first_search(share->g, *orig,
904+ visitor(make_bfs_visitor(
905+ std::make_pair(
906+ record_predecessors(
907+ make_iterator_property_map(p.begin(),
908+ share->indexmap),
909+ on_tree_edge()
910+ ),
911+ std::make_pair(
912+ record_distances(
913+ make_iterator_property_map(d.begin(),
914+ share->indexmap),
915+ on_tree_edge()
916+ ),
917+ vis
918+ ))
919+ ))
920+ );
921+ break;
922+ default:
923+ abort();
924+ }
925+ }
926+ break;
927+
928+ case BREADTH_FIRST | HAVE_DEST:
929+ case DIJKSTRAS | HAVE_DEST:
930+ if ((cursor= new stack_cursor(share)) && (orig || dest))
931+ {
932+ std::vector<Vertex> p(num_vertices(share->g));
933+ std::vector<EdgeWeight> d(num_vertices(share->g));
934+ oqgraph_visit_dist vis(p.begin(), d.begin(),
935+ static_cast<stack_cursor*>(cursor));
936+ reverse_graph<Graph> r(share->g);
937+ p[share->indexmap[*dest]]= *dest;
938+ switch (ALGORITHM & op)
939+ {
940+ case DIJKSTRAS:
941+ dijkstra_shortest_paths(r, *dest,
942+ weight_map(
943+ share->weightmap
944+ ).
945+ distance_map(
946+ make_iterator_property_map(d.begin(), share->indexmap)
947+ ).
948+ predecessor_map(
949+ make_iterator_property_map(p.begin(), share->indexmap)
950+ ).
951+ visitor(
952+ make_dijkstra_visitor(vis)
953+ )
954+ );
955+ break;
956+ case BREADTH_FIRST:
957+ breadth_first_search(r, *dest,
958+ visitor(make_bfs_visitor(
959+ std::make_pair(
960+ record_predecessors(
961+ make_iterator_property_map(p.begin(),
962+ share->indexmap),
963+ on_tree_edge()
964+ ),
965+ std::make_pair(
966+ record_distances(
967+ make_iterator_property_map(d.begin(),
968+ share->indexmap),
969+ on_tree_edge()
970+ ),
971+ vis
972+ ))
973+ ))
974+ );
975+ break;
976+ default:
977+ abort();
978+ }
979+ }
980+ break;
981+
982+ default:
983+ break;
984+ }
985+ return 0;
986+ //}
987+ //catch (...)
988+ //{
989+ // return MISC_FAIL;
990+ //}
991+ }
992+
993+ int oqgraph::fetch_row(row& result) throw()
994+ {
995+ if (!cursor)
996+ return NO_MORE_DATA;
997+ return cursor->fetch_row(row_info, result);
998+ }
999+
1000+ int oqgraph::fetch_row(row& result, const void* ref_ptr) throw()
1001+ {
1002+ const reference &ref= *(const reference*) ref_ptr;
1003+ if (!cursor)
1004+ return NO_MORE_DATA;
1005+ return cursor->fetch_row(row_info, result, ref);
1006+ }
1007+
1008+ void oqgraph::row_ref(void *ref_ptr) throw()
1009+ {
1010+ reference &ref= *(reference*) ref_ptr;
1011+ if (cursor)
1012+ cursor->current(ref);
1013+ else
1014+ ref= reference();
1015+ }
1016+
1017+ int oqgraph::random(bool scan) throw()
1018+ {
1019+ if (scan || !cursor)
1020+ {
1021+ delete cursor; cursor= 0;
1022+ if (!(cursor= new edges_cursor(share)))
1023+ return MISC_FAIL;
1024+ }
1025+ row_info= empty_row;
1026+ return OK;
1027+ }
1028+
1029+ void oqgraph::free(oqgraph *graph) throw()
1030+ {
1031+ delete graph;
1032+ }
1033+
1034+ void oqgraph::free(oqgraph_share *graph) throw()
1035+ {
1036+ delete graph;
1037+ }
1038+
1039+ const size_t oqgraph::sizeof_ref= sizeof(reference);
1040+}
1041+
1042+int stack_cursor::fetch_row(const row &row_info, row &result)
1043+{
1044+ if (!results.empty())
1045+ {
1046+ if (int res= fetch_row(row_info, result, results.top()))
1047+ return res;
1048+ results.pop();
1049+ return oqgraph::OK;
1050+ }
1051+ else
1052+ {
1053+ last= reference();
1054+ return oqgraph::NO_MORE_DATA;
1055+ }
1056+}
1057+
1058+int stack_cursor::fetch_row(const row &row_info, row &result,
1059+ const reference &ref)
1060+{
1061+ last= ref;
1062+ if (optional<Vertex> v= last.vertex())
1063+ {
1064+ optional<int> seq;
1065+ optional<EdgeWeight> w;
1066+ optional<Vertex> v;
1067+ result= row_info;
1068+ if ((result.seq_indicator= seq= last.sequence()))
1069+ result.seq= *seq;
1070+ if ((result.link_indicator= v= last.vertex()))
1071+ result.link= share->idmap[*v];
1072+ if ((result.weight_indicator= w= last.weight()))
1073+ result.weight= *w;
1074+ return oqgraph::OK;
1075+ }
1076+ else
1077+ return oqgraph::NO_MORE_DATA;
1078+}
1079+
1080+
1081+int vertices_cursor::fetch_row(const row &row_info, row &result)
1082+{
1083+ vertex_iterator it, end;
1084+ reference ref;
1085+ size_t count= position;
1086+ for (tie(it, end)= vertices(share->g); count && it != end; ++it, --count);
1087+ if (it != end)
1088+ ref= reference(position+1, *it);
1089+ if (int res= fetch_row(row_info, result, ref))
1090+ return res;
1091+ position++;
1092+ return oqgraph::OK;
1093+}
1094+
1095+int vertices_cursor::fetch_row(const row &row_info, row &result,
1096+ const reference &ref)
1097+{
1098+ last= ref;
1099+ optional<Vertex> v= last.vertex();
1100+ result= row_info;
1101+ if (v)
1102+ {
1103+ result.link_indicator= 1;
1104+ result.link= share->idmap[*v];
1105+#ifdef DISPLAY_VERTEX_INFO
1106+ result.seq_indicator= 1;
1107+ if ((result.seq= degree(*v, share->g)))
1108+ {
1109+ EdgeWeight weight= 0;
1110+ graph_traits<Graph>::in_edge_iterator iei, iei_end;
1111+ for (tie(iei, iei_end)= in_edges(*v, share->g); iei != iei_end; ++iei)
1112+ weight+= share->weightmap[*iei];
1113+ graph_traits<Graph>::out_edge_iterator oei, oei_end;
1114+ for (tie(oei, oei_end)= out_edges(*v, share->g); oei != oei_end; ++oei)
1115+ weight+= share->weightmap[*oei];
1116+ result.weight_indicator= 1;
1117+ result.weight= weight / result.seq;
1118+ }
1119+#endif
1120+ return oqgraph::OK;
1121+ }
1122+ else
1123+ return oqgraph::NO_MORE_DATA;
1124+}
1125+
1126+int edges_cursor::fetch_row(const row &row_info, row &result)
1127+{
1128+ edge_iterator it, end;
1129+ reference ref;
1130+ size_t count= position;
1131+ for (tie(it, end)= edges(share->g); count && it != end; ++it, --count);
1132+ if (it != end)
1133+ ref= reference(position+1, *it);
1134+ if (int res= fetch_row(row_info, result, ref))
1135+ return res;
1136+ ++position;
1137+ return oqgraph::OK;
1138+}
1139+
1140+int edges_cursor::fetch_row(const row &row_info, row &result,
1141+ const reference &ref)
1142+{
1143+ optional<Edge> edge;
1144+ if ((edge= (last= ref).edge()))
1145+ {
1146+ result= row_info;
1147+ result.orig_indicator= result.dest_indicator= result.weight_indicator= 1;
1148+ result.orig= share->idmap[ source( *edge, share->g ) ];
1149+ result.dest= share->idmap[ target( *edge, share->g ) ];
1150+ result.weight= share->weightmap[ *edge ];
1151+ return oqgraph::OK;
1152+ }
1153+ return oqgraph::NO_MORE_DATA;
1154+}
1155+
1156+namespace boost {
1157+ GRAPHCORE_INTERNAL void throw_exception(std::exception const&)
1158+ {
1159+ abort();
1160+ }
1161+}
1162
1163=== added file 'oqgraph/graphcore.h'
1164--- oqgraph/graphcore.h 1970-01-01 00:00:00 +0000
1165+++ oqgraph/graphcore.h 2009-10-25 07:55:23 +0000
1166@@ -0,0 +1,116 @@
1167+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
1168+
1169+ This program is free software; you can redistribute it and/or modify
1170+ it under the terms of the GNU General Public License as published by
1171+ the Free Software Foundation; version 2 of the License, or
1172+ (at your option) any later version.
1173+
1174+ This program is distributed in the hope that it will be useful,
1175+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1176+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1177+ GNU General Public License for more details.
1178+
1179+ You should have received a copy of the GNU General Public License
1180+ along with this program; if not, write to the Free Software
1181+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
1182+
1183+/* ======================================================================
1184+ Open Query Graph Computation Engine, based on a concept by Arjen Lentz
1185+ Mk.II implementation by Antony Curtis & Arjen Lentz
1186+ For more information, documentation, support, enhancement engineering,
1187+ and non-GPL licensing, see http://openquery.com/graph
1188+ or contact graph@openquery.com
1189+ For packaged binaries, see http://ourdelta.org
1190+ ======================================================================
1191+*/
1192+
1193+#ifndef oq_graphcore_h_
1194+#define oq_graphcore_h_
1195+
1196+/* #define GRAPHCORE_INTERNAL __attribute__((visibility("hidden"))) */
1197+#define GRAPHCORE_INTERNAL
1198+
1199+#include "graphcore-types.h"
1200+
1201+namespace open_query
1202+{
1203+ class oqgraph_share;
1204+ class oqgraph_cursor;
1205+
1206+ struct row
1207+ {
1208+ bool latch_indicator;
1209+ bool orig_indicator;
1210+ bool dest_indicator;
1211+ bool weight_indicator;
1212+ bool seq_indicator;
1213+ bool link_indicator;
1214+
1215+ int latch;
1216+ VertexID orig;
1217+ VertexID dest;
1218+ EdgeWeight weight;
1219+ unsigned seq;
1220+ VertexID link;
1221+ };
1222+
1223+ class oqgraph
1224+ {
1225+ oqgraph_share *const share;
1226+ oqgraph_cursor *cursor;
1227+ row row_info;
1228+
1229+ inline oqgraph(oqgraph_share*) throw();
1230+ inline ~oqgraph() throw();
1231+ public:
1232+
1233+ enum error_code
1234+ {
1235+ OK= 0,
1236+ NO_MORE_DATA,
1237+ EDGE_NOT_FOUND,
1238+ INVALID_WEIGHT,
1239+ DUPLICATE_EDGE,
1240+ CANNOT_ADD_VERTEX,
1241+ CANNOT_ADD_EDGE,
1242+ MISC_FAIL
1243+ };
1244+
1245+ struct current_row_st {};
1246+ static inline current_row_st current_row()
1247+ { return current_row_st(); }
1248+
1249+ unsigned vertices_count() const throw();
1250+ unsigned edges_count() const throw();
1251+
1252+ int delete_all(void) throw();
1253+
1254+ int insert_edge(VertexID, VertexID, EdgeWeight, bool=0) throw();
1255+ int modify_edge(VertexID, VertexID, EdgeWeight) throw();
1256+ int delete_edge(VertexID, VertexID) throw();
1257+
1258+ int modify_edge(current_row_st,
1259+ VertexID*, VertexID*, EdgeWeight*, bool=0) throw();
1260+ int delete_edge(current_row_st) throw();
1261+
1262+ int replace_edge(VertexID orig, VertexID dest, EdgeWeight weight) throw()
1263+ { return insert_edge(orig, dest, weight, true); }
1264+
1265+ int search(int*, VertexID*, VertexID*) throw();
1266+ int random(bool) throw();
1267+
1268+ int fetch_row(row&) throw();
1269+ int fetch_row(row&, const void*) throw();
1270+ void row_ref(void*) throw();
1271+
1272+ static oqgraph* create(oqgraph_share*) throw();
1273+ static oqgraph_share *create() throw();
1274+
1275+ static void free(oqgraph*) throw();
1276+ static void free(oqgraph_share*) throw();
1277+
1278+ static const size_t sizeof_ref;
1279+ };
1280+
1281+}
1282+#endif
1283
1284=== added file 'oqgraph/graphstore.c'
1285--- oqgraph/graphstore.c 1970-01-01 00:00:00 +0000
1286+++ oqgraph/graphstore.c 2009-10-25 07:55:23 +0000
1287@@ -0,0 +1,356 @@
1288+/*
1289+ * Graph Engine - Copyright (C) 2007 by Arjen Lentz (arjen@openquery.com.au)
1290+ * graphstore.c internal storage system
1291+ */
1292+#include <stdlib.h>
1293+#include <string.h>
1294+#include <my_global.h>
1295+#include <my_sys.h>
1296+#include "graphstore.h"
1297+
1298+
1299+/*
1300+ create a new vertex, and add it to the list (or start a list)
1301+ NOTE! gspp is ptr to base ptr
1302+
1303+ returns 1 for ok, 0 for error
1304+*/
1305+static int _add_vertex (GRAPHSTORE **gspp, GRAPH_VERTEXID id)
1306+{
1307+ GRAPHSTORE *newgsp;
1308+ GRAPHSTORE *gscurp;
1309+
1310+ if (gspp == NULL)
1311+ return 0;
1312+
1313+ /* not allowing 0 */
1314+ if (!id)
1315+ return 0;
1316+
1317+ if (*gspp != NULL) {
1318+ for (gscurp = *gspp; gscurp != NULL; gscurp = gscurp->next) {
1319+ if (gscurp->vertex->id == id)
1320+ return 1; /* we can ignore, id already exists */
1321+ }
1322+ }
1323+
1324+ /* allocate and initialise */
1325+ if ((newgsp = my_malloc(sizeof (GRAPHSTORE),MYF(MY_ZEROFILL))) == NULL)
1326+ return 0;
1327+
1328+ if ((newgsp->vertex = my_malloc(sizeof (GRAPH_VERTEX),MYF(MY_ZEROFILL))) == NULL) {
1329+ my_free(newgsp,MYF(0));
1330+ return 0;
1331+ }
1332+
1333+ newgsp->vertex->id = id;
1334+ /* add new vertex to end of list */
1335+ if (*gspp != NULL) {
1336+ for (gscurp = *gspp; gscurp->next != NULL; gscurp = gscurp->next);
1337+ gscurp->next = newgsp;
1338+ }
1339+ else /* new list */
1340+ *gspp = newgsp;
1341+
1342+ /* ok */
1343+ return 1;
1344+}
1345+
1346+
1347+/*
1348+ find a vertex by id
1349+
1350+ returns ptr or NULL
1351+*/
1352+static GRAPH_VERTEX *_find_vertex (GRAPHSTORE *gsp, GRAPH_VERTEXID id)
1353+{
1354+ /* just loop through the list to find id */
1355+ while (gsp != NULL && gsp->vertex->id != id)
1356+ gsp = gsp->next;
1357+
1358+ /* return ptr to vertex, or NULL */
1359+ return (gsp != NULL ? gsp->vertex : NULL);
1360+}
1361+
1362+
1363+/*
1364+ add edge
1365+ both vertices must already exist; graphstore_insert() does this
1366+
1367+ return 1 for ok, 0 for error (already exists, alloc error, etc)
1368+*/
1369+static int _add_edge (GRAPHSTORE *gsp, GRAPH_VERTEXID origid, GRAPH_VERTEXID destid, GRAPH_WEIGHT weight)
1370+{
1371+ GRAPH_VERTEX *origvp, *destvp;
1372+ GRAPH_EDGE *ep, *newep;
1373+
1374+ /* find both vertices */
1375+ if ((origvp = _find_vertex(gsp,origid)) == NULL ||
1376+ (destvp = _find_vertex(gsp,destid)) == NULL)
1377+ return 0;
1378+
1379+ /* check if edge already exists */
1380+ for (ep = origvp->forward_edge; ep != NULL; ep = ep->next_edge) {
1381+ if (ep->vertex->id == destid)
1382+ return 0;
1383+ }
1384+
1385+ /* allocate and initialise new edge */
1386+ if ((newep = my_malloc(sizeof (GRAPH_EDGE),MYF(MY_ZEROFILL))) == NULL)
1387+ return 0;
1388+
1389+ newep->vertex = destvp;
1390+ newep->weight = weight;
1391+
1392+ /* insert new edge at start of chain, that's easiest */
1393+ ep = origvp->forward_edge;
1394+ origvp->forward_edge = newep;
1395+ newep->next_edge = ep;
1396+
1397+ /* ok */
1398+ return 1;
1399+}
1400+
1401+
1402+/*
1403+ create a new row, and add it to the graph set (or start set)
1404+ NOTE! gsetpp is ptr to base ptr
1405+
1406+ returns 1 for ok, 0 for error
1407+*/
1408+static int _add_graph_set (GRAPH_SET **gsetpp, GRAPH_TUPLE *gtp)
1409+{
1410+ GRAPH_SET *newgsetp;
1411+ GRAPH_SET *gsetcurp;
1412+
1413+ if (gsetpp == NULL || gtp == NULL)
1414+ return 0;
1415+
1416+ /* allocate and initialise */
1417+ if ((newgsetp = my_malloc(sizeof (GRAPH_SET),MYF(MY_ZEROFILL))) == NULL)
1418+ return 0;
1419+
1420+ /* put in the data */
1421+ memcpy(&newgsetp->tuple,gtp,sizeof (GRAPH_TUPLE));
1422+
1423+ /* add new row to end of set */
1424+ if (*gsetpp != NULL) {
1425+ for (gsetcurp = *gsetpp; gsetcurp->next != NULL; gsetcurp = gsetcurp->next);
1426+ gsetcurp->next = newgsetp;
1427+ }
1428+ else { /* new set */
1429+ *gsetpp = newgsetp;
1430+ }
1431+
1432+ /* ok */
1433+ return 1;
1434+}
1435+
1436+
1437+/*
1438+ free a graph set (release memory)
1439+
1440+ returns 1 for ok, 0 for error
1441+*/
1442+int free_graph_set (GRAPH_SET *gsetp)
1443+{
1444+ GRAPH_SET *nextgsetp;
1445+
1446+ if (gsetp == NULL)
1447+ return 0;
1448+
1449+ while (gsetp != NULL) {
1450+ nextgsetp = gsetp->next;
1451+ /* free() is a void function, nothing to check */
1452+ my_free(gsetp,MYF(0));
1453+ gsetp = nextgsetp;
1454+ }
1455+
1456+ /* ok */
1457+ return 1;
1458+}
1459+
1460+
1461+/*
1462+ insert new data into graphstore
1463+ this can be either a vertex or an edge, depending on the params
1464+ NOTE! gspp is ptr to base ptr
1465+
1466+ returns 1 for ok, 0 for error
1467+*/
1468+int graphstore_insert (GRAPHSTORE **gspp, GRAPH_TUPLE *gtp)
1469+{
1470+ if (gspp == NULL)
1471+ return 0;
1472+
1473+ /* if nada or no orig vertex, we can't do anything */
1474+ if (gtp == NULL || !gtp->origid)
1475+ return 0;
1476+
1477+#if 0
1478+printf("inserting: origid=%lu destid=%lu weight=%lu\n",gtp->origid,gtp->destid,gtp->weight);
1479+#endif
1480+
1481+ if (!gtp->destid) /* no edge param so just adding vertex */
1482+ return _add_vertex(gspp,gtp->origid);
1483+
1484+ /*
1485+ add an edge
1486+ first add both vertices just in case they didn't yet exist...
1487+ not checking result there: if there's a prob, _add_edge() will catch.
1488+ */
1489+ _add_vertex(gspp,gtp->origid);
1490+ _add_vertex(gspp,gtp->destid);
1491+ return _add_edge(*gspp,gtp->origid,gtp->destid,gtp->weight);
1492+}
1493+
1494+
1495+/*
1496+ this is an internal function used by graphstore_query()
1497+
1498+ find any path from originating vertex to destid
1499+ if found, add to the result set on the way back
1500+ NOTE: recursive function!
1501+
1502+ returns 1 for hit, 0 for nothing, -1 for error
1503+*/
1504+int _find_any_path(GRAPH_SET **gsetpp, GRAPH_VERTEXID origid, GRAPH_VERTEXID destid, GRAPH_VERTEX *gvp, GRAPH_SEQ depth)
1505+{
1506+ GRAPH_EDGE *gep;
1507+ GRAPH_TUPLE tup;
1508+ int res;
1509+
1510+ if (gvp->id == destid) {
1511+ /* found target! */
1512+ bzero(&tup,sizeof (GRAPH_TUPLE));
1513+ tup.origid = origid;
1514+ tup.destid = destid;
1515+ tup.seq = depth;
1516+ tup.linkid = gvp->id;
1517+ return (_add_graph_set(gsetpp,&tup) ? 1 : -1);
1518+ }
1519+
1520+ /* walk through all edges for this vertex */
1521+ for (gep = gvp->forward_edge; gep; gep = gep->next_edge) {
1522+ /* recurse */
1523+ res = _find_any_path(gsetpp,origid,destid,gep->vertex,depth+1);
1524+ if (res < 0)
1525+ return res;
1526+ if (res > 0) {
1527+ /* found somewhere below this one, insert ourselves and return */
1528+ bzero(&tup,sizeof (GRAPH_TUPLE));
1529+ tup.origid = origid;
1530+ tup.destid = destid;
1531+ tup.weight = gep->weight;
1532+ tup.seq = depth;
1533+ tup.linkid = gvp->id;
1534+ return (_add_graph_set(gsetpp,&tup) ? 1 : -1);
1535+ }
1536+ }
1537+
1538+ /* nothing found but no error */
1539+ return 0;
1540+}
1541+
1542+
1543+/*
1544+ query graphstore
1545+ latch specifies what operation to perform
1546+
1547+ we need to feed the conditions in... (through engine condition pushdown)
1548+ for now we just presume one condition per field so we just feed in a tuple
1549+ this also means we can just find constants, not ranges
1550+
1551+ return ptr to GRAPH_SET
1552+ caller must free with free_graph_set()
1553+*/
1554+GRAPH_SET *graphstore_query (GRAPHSTORE *gsp, GRAPH_TUPLE *gtp)
1555+{
1556+ GRAPH_SET *gsetp = NULL;
1557+ GRAPH_SET *gsetcurp;
1558+ GRAPH_SET *newgsetp;
1559+
1560+ if (gsp == NULL || gtp == NULL)
1561+ return (NULL);
1562+
1563+ switch (gtp->latch) {
1564+ case 0: /* return all vertices/edges */
1565+ {
1566+ GRAPHSTORE *gscurp;
1567+ GRAPH_EDGE *gep;
1568+ GRAPH_TUPLE tup;
1569+
1570+ /* walk through all vertices */
1571+ for (gscurp = gsp; gscurp != NULL; gscurp = gscurp->next) {
1572+ /* check for condition */
1573+ if (gtp->origid && gscurp->vertex->id != gtp->origid)
1574+ continue;
1575+
1576+ bzero(&tup,sizeof (GRAPH_TUPLE));
1577+ tup.origid = gscurp->vertex->id;
1578+
1579+ /* no edges? */
1580+ if (gscurp->vertex->forward_edge == NULL) {
1581+ /* just add vertex to set */
1582+ if (!_add_graph_set(&gsetp,&tup)) {
1583+ if (gsetp != NULL) /* clean up */
1584+ my_free(gsetp,MYF(0));
1585+ return (NULL);
1586+ }
1587+ }
1588+ else {
1589+ /* walk through all edges */
1590+ for (gep = gscurp->vertex->forward_edge; gep; gep = gep->next_edge) {
1591+ tup.destid = gep->vertex->id;
1592+ tup.weight = gep->weight;
1593+
1594+ /* just add vertex to set */
1595+ if (!_add_graph_set(&gsetp,&tup)) {
1596+ if (gsetp != NULL) /* clean up */
1597+ my_free(gsetp,MYF(0));
1598+ return (NULL);
1599+ }
1600+ }
1601+ }
1602+ }
1603+ }
1604+ break;
1605+
1606+ case 1: /* find a path between origid and destid */
1607+ /* yes it'll just go with the first path it finds! */
1608+ {
1609+ GRAPHSTORE *gscurp;
1610+ GRAPH_VERTEX *origvp;
1611+ GRAPH_TUPLE tup;
1612+
1613+ if (!gtp->origid || !gtp->destid)
1614+ return NULL;
1615+
1616+ /* find both vertices */
1617+ if ((origvp = _find_vertex(gsp,gtp->origid)) == NULL ||
1618+ _find_vertex(gsp,gtp->destid) == NULL)
1619+ return NULL;
1620+
1621+ if (_find_any_path(&gsetp,gtp->origid,gtp->destid,origvp,0) < 0) { /* error? */
1622+ if (gsetp != NULL) /* clean up */
1623+ my_free(gsetp,MYF(0));
1624+ return NULL;
1625+ }
1626+ }
1627+ break;
1628+
1629+ default:
1630+ /* this ends up being an empty set */
1631+ break;
1632+ }
1633+
1634+ /* Fix up latch column with the proper value - to be relationally correct */
1635+ for (gsetcurp = gsetp; gsetcurp != NULL; gsetcurp = gsetcurp->next)
1636+ gsetcurp->tuple.latch = gtp->latch;
1637+
1638+ return gsetp;
1639+}
1640+
1641+
1642+
1643+/* end of graphstore.c */
1644\ No newline at end of file
1645
1646=== added file 'oqgraph/graphstore.h'
1647--- oqgraph/graphstore.h 1970-01-01 00:00:00 +0000
1648+++ oqgraph/graphstore.h 2009-10-25 07:55:23 +0000
1649@@ -0,0 +1,90 @@
1650+/*
1651+ * Graph Engine - Copyright (C) 2007 by Arjen Lentz (arjen@openquery.com.au)
1652+ * graphstore.h internal storage system
1653+ */
1654+//typedef unsigned short uint16;
1655+//typedef unsigned long long uint64;
1656+
1657+
1658+/*
1659+ This is essentially what a GRAPH engine table looks like on the MySQL end:
1660+ CREATE TABLE foo (
1661+ latch SMALLINT UNSIGNED NULL,
1662+ origid BIGINT UNSIGNED NULL,
1663+ destid BIGINT UNSIGNED NULL,
1664+ weight BIGINT UNSIGNED NULL,
1665+ seq BIGINT UNSIGNED NULL,
1666+ linkid BIGINT UNSIGNED NULL
1667+ ) ENGINE=OQGRAPH
1668+*/
1669+
1670+
1671+/*
1672+ We represent the above in C in the following way:
1673+*/
1674+typedef uint16 GRAPH_LATCH;
1675+typedef uint64 GRAPH_VERTEXID;
1676+typedef uint64 GRAPH_WEIGHT;
1677+typedef uint64 GRAPH_SEQ;
1678+
1679+typedef struct graph_tuple {
1680+ GRAPH_LATCH latch; /* function */
1681+ GRAPH_VERTEXID origid; /* vertex (should be != 0) */
1682+ GRAPH_VERTEXID destid; /* edge */
1683+ GRAPH_WEIGHT weight; /* weight */
1684+ GRAPH_SEQ seq; /* seq# within (origid) */
1685+ GRAPH_VERTEXID linkid; /* current step between origid/destid */
1686+} GRAPH_TUPLE;
1687+
1688+typedef struct graph_set {
1689+ GRAPH_TUPLE tuple;
1690+ struct graph_set *next;
1691+} GRAPH_SET;
1692+
1693+
1694+/*
1695+ Internally, sets look nothing like the above
1696+
1697+ - We have vertices, connected by edges.
1698+ - Each vertex' edges are maintained in a linked list.
1699+ - Edges can be weighted.
1700+
1701+ There are some issues with this structure, it'd be a pest to do a delete
1702+ So for now, let's just not support deletes!
1703+*/
1704+/* the below is half-gross and will likely change */
1705+typedef struct graph_edge {
1706+ struct graph_vertex {
1707+ GRAPH_VERTEXID id;
1708+ struct graph_edge *forward_edge;
1709+ } *vertex;
1710+ GRAPH_WEIGHT weight;
1711+ struct graph_edge *next_edge;
1712+} GRAPH_EDGE;
1713+
1714+typedef struct graph_vertex GRAPH_VERTEX;
1715+
1716+
1717+/*
1718+ A rough internal storage system for a set
1719+*/
1720+/* this below is fully gross and will definitely change */
1721+typedef struct graphstore {
1722+ GRAPH_VERTEX *vertex; /* changed to ptr when integrating into MySQL */
1723+ struct graphstore *next;
1724+} GRAPHSTORE;
1725+
1726+#ifdef __cplusplus
1727+extern "C" {
1728+#endif
1729+
1730+/* public function declarations */
1731+int graphstore_insert (GRAPHSTORE **gspp, GRAPH_TUPLE *gtp);
1732+GRAPH_SET *graphstore_query (GRAPHSTORE *gsp, GRAPH_TUPLE *gtp);
1733+int free_graph_set (GRAPH_SET *gsetp);
1734+
1735+#ifdef __cplusplus
1736+}
1737+#endif
1738+
1739+/* end of graphstore.h */
1740\ No newline at end of file
1741
1742=== added file 'oqgraph/ha_oqgraph.cc'
1743--- oqgraph/ha_oqgraph.cc 1970-01-01 00:00:00 +0000
1744+++ oqgraph/ha_oqgraph.cc 2009-10-25 07:55:23 +0000
1745@@ -0,0 +1,884 @@
1746+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
1747+ Portions of this file copyright (C) 2000-2006 MySQL AB
1748+
1749+ This program is free software; you can redistribute it and/or modify
1750+ it under the terms of the GNU General Public License as published by
1751+ the Free Software Foundation; version 2 of the License.
1752+
1753+ This program is distributed in the hope that it will be useful,
1754+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1755+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1756+ GNU General Public License for more details.
1757+
1758+ You should have received a copy of the GNU General Public License
1759+ along with this program; if not, write to the Free Software
1760+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
1761+
1762+/* ======================================================================
1763+ Open Query Graph Computation Engine, based on a concept by Arjen Lentz
1764+ Mk.II implementation by Antony Curtis & Arjen Lentz
1765+ For more information, documentation, support, enhancement engineering,
1766+ and non-GPL licensing, see http://openquery.com/graph
1767+ or contact graph@openquery.com
1768+ For packaged binaries, see http://ourdelta.org
1769+ ======================================================================
1770+*/
1771+
1772+#include "drizzled/server_includes.h"
1773+#include "drizzled/error.h"
1774+#include "drizzled/plugin.h"
1775+#include "drizzled/session.h"
1776+#include "drizzled/table.h"
1777+#include "drizzled/plugin/storage_engine.h"
1778+
1779+#include "ha_oqgraph.h"
1780+#include "open_tables.h"
1781+#include "graphcore.h"
1782+
1783+#define OQGRAPH_STATS_UPDATE_THRESHOLD 10
1784+
1785+using namespace std;
1786+using namespace open_query;
1787+
1788+static drizzled::plugin::StorageEngine *oqgraph_engine_ptr= NULL;
1789+
1790+static const char *ha_oqgraph_exts[] =
1791+{
1792+ NULL
1793+};
1794+
1795+class OqgraphEngine : public drizzled::plugin::StorageEngine
1796+{
1797+public:
1798+ OqgraphEngine(string name_arg)
1799+ :
1800+ drizzled::plugin::StorageEngine(name_arg,
1801+ HTON_CAN_RECREATE)
1802+ {}
1803+
1804+ const char **bas_ext() const
1805+ {
1806+ return ha_oqgraph_exts;
1807+ }
1808+
1809+ virtual Cursor *create(TableShare *table,
1810+ MEM_ROOT *mem_root)
1811+ {
1812+ return new(mem_root) ha_oqgraph(this, table);
1813+ }
1814+
1815+ int createTableImplementation(Session *session,
1816+ const char *table_name,
1817+ Table *form,
1818+ HA_CREATE_INFO *create_info,
1819+ drizzled::message::Table *);
1820+
1821+ int deleteTableImplementation(Session *session,
1822+ const string table_path);
1823+
1824+ int renameTableImplementation(Session *session,
1825+ const char *from,
1826+ const char *to);
1827+};
1828+
1829+#define STATISTIC_INCREMENT(X) ha_statistic_increment(&SSV::X)
1830+#define MOVE(X) move_field_offset(X)
1831+#define RECORDS stats.records
1832+
1833+static int oqgraph_init(drizzled::plugin::Registry &registry)
1834+{
1835+ oqgraph_engine_ptr= new(std::nothrow) OqgraphEngine("OQGRAPH");
1836+ if (! oqgraph_engine_ptr)
1837+ {
1838+ return 1;
1839+ }
1840+
1841+ registry.add(oqgraph_engine_ptr);
1842+
1843+ return 0;
1844+}
1845+
1846+static int oqgraph_fini(drizzled::plugin::Registry &registry)
1847+{
1848+ registry.remove(oqgraph_engine_ptr);
1849+ delete oqgraph_engine_ptr;
1850+
1851+ return 0;
1852+}
1853+
1854+static int error_code(int res)
1855+{
1856+ switch (res)
1857+ {
1858+ case oqgraph::OK:
1859+ return 0;
1860+ case oqgraph::NO_MORE_DATA:
1861+ return HA_ERR_END_OF_FILE;
1862+ case oqgraph::EDGE_NOT_FOUND:
1863+ return HA_ERR_KEY_NOT_FOUND;
1864+ case oqgraph::INVALID_WEIGHT:
1865+ return HA_ERR_AUTOINC_ERANGE;
1866+ case oqgraph::DUPLICATE_EDGE:
1867+ return HA_ERR_FOUND_DUPP_KEY;
1868+ case oqgraph::CANNOT_ADD_VERTEX:
1869+ case oqgraph::CANNOT_ADD_EDGE:
1870+ return HA_ERR_RECORD_FILE_FULL;
1871+ case oqgraph::MISC_FAIL:
1872+ default:
1873+ return HA_ERR_CRASHED_ON_USAGE;
1874+ }
1875+}
1876+
1877+/**
1878+ * Check if table complies with our designated structure
1879+ *
1880+ * ColName Type Attributes
1881+ * ======= ======== =============
1882+ * latch INT NULL
1883+ * origid BIGINT NULL
1884+ * destid BIGINT NULL
1885+ * weight DOUBLE NULL
1886+ * seq BIGINT NULL
1887+ * linkid BIGINT NULL
1888+ * =================================
1889+ *
1890+ CREATE TABLE foo (
1891+ latch INT NULL,
1892+ origid BIGINT NULL,
1893+ destid BIGINT NULL,
1894+ weight DOUBLE NULL,
1895+ seq BIGINT NULL,
1896+ linkid BIGINT NULL,
1897+ KEY (latch, origid, destid) USING HASH,
1898+ KEY (latch, destid, origid) USING HASH
1899+ ) ENGINE=OQGRAPH
1900+
1901+ */
1902+static int oqgraph_check_table_structure (Table *table_arg)
1903+{
1904+ int i;
1905+ struct { const char *colname; int coltype; } skel[] = {
1906+ { "latch" , DRIZZLE_TYPE_LONG },
1907+ { "origid", DRIZZLE_TYPE_LONGLONG },
1908+ { "destid", DRIZZLE_TYPE_LONGLONG },
1909+ { "weight", DRIZZLE_TYPE_DOUBLE },
1910+ { "seq" , DRIZZLE_TYPE_LONGLONG },
1911+ { "linkid", DRIZZLE_TYPE_LONGLONG },
1912+ { NULL , 0}
1913+ };
1914+
1915+ Field **field= table_arg->field;
1916+ for (i= 0; *field && skel[i].colname; i++, field++) {
1917+ /* Check Column Type */
1918+ if ((*field)->type() != skel[i].coltype)
1919+ return -1;
1920+ /* Check THAT NOT NULL isn't set */
1921+ if ((*field)->flags & NOT_NULL_FLAG)
1922+ return -1;
1923+ /* Check the column name */
1924+ if (strcmp(skel[i].colname,(*field)->field_name))
1925+ return -1;
1926+ }
1927+
1928+ if (skel[i].colname || *field || !table_arg->key_info || !table_arg->s->keys)
1929+ return -1;
1930+
1931+ KEY *key= table_arg->key_info;
1932+ for (uint32_t x= 0; x < table_arg->s->keys; ++x, ++key)
1933+ {
1934+ Field **ot_field= table_arg->field;
1935+ /* check that the first key part is the latch and it is a hash key */
1936+ if (!(ot_field[0] == key->key_part[0].field &&
1937+ HA_KEY_ALG_HASH == key->algorithm))
1938+ return -1;
1939+ if (key->key_parts == 3)
1940+ {
1941+ /* KEY (latch, origid, destid) USING HASH */
1942+ /* KEY (latch, destid, origid) USING HASH */
1943+ if (! (ot_field[1] == key->key_part[1].field &&
1944+ ot_field[2] == key->key_part[2].field) &&
1945+ ! (ot_field[1] == key->key_part[2].field &&
1946+ ot_field[2] == key->key_part[1].field))
1947+ return -1;
1948+ }
1949+ else
1950+ return -1;
1951+ }
1952+
1953+ return 0;
1954+}
1955+
1956+/*****************************************************************************
1957+** OQGRAPH tables
1958+*****************************************************************************/
1959+
1960+ha_oqgraph::ha_oqgraph(drizzled::plugin::StorageEngine *engine_arg,
1961+ TableShare *table_arg)
1962+ :
1963+ Cursor(engine_arg, table_arg),
1964+ share(0),
1965+ graph(0),
1966+ records_changed(0),
1967+ key_stat_version(0)
1968+{ }
1969+
1970+
1971+
1972+uint64_t ha_oqgraph::table_flags() const
1973+{
1974+ return (HA_NO_BLOBS | HA_NULL_IN_KEY |
1975+ HA_REC_NOT_IN_SEQ);
1976+}
1977+
1978+uint32_t ha_oqgraph::index_flags(uint32_t, uint32_t, bool) const
1979+{
1980+ return (HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
1981+}
1982+
1983+int ha_oqgraph::open(const char *name, int, uint32_t)
1984+{
1985+ OpenTables &open_tables= OpenTables::singleton();
1986+ if ((share = open_tables.getShare(name)))
1987+ {
1988+ ref_length= oqgraph::sizeof_ref;
1989+ }
1990+
1991+ if (share)
1992+ {
1993+ /* Initialize variables for the opened table */
1994+ thr_lock_data_init(&share->lock, &lock, NULL);
1995+
1996+ graph= oqgraph::create(share->graph);
1997+
1998+ /*
1999+ We cannot run update_key_stats() here because we do not have a
2000+ lock on the table. The 'records' count might just be changed
2001+ temporarily at this moment and we might get wrong statistics (Bug
2002+ #10178). Instead we request for update. This will be done in
2003+ ha_oqgraph::info(), which is always called before key statistics are
2004+ used.
2005+ */
2006+ key_stat_version= share->key_stat_version-1;
2007+ }
2008+
2009+ return (share ? 0 : 1);
2010+}
2011+
2012+int ha_oqgraph::close(void)
2013+{
2014+ oqgraph::free(graph);
2015+ graph= 0;
2016+ OpenTables &open_tables= OpenTables::singleton();
2017+ open_tables.freeShare();
2018+ return error_code(0);
2019+}
2020+
2021+void ha_oqgraph::update_key_stats()
2022+{
2023+ for (uint i= 0; i < table->s->keys; i++)
2024+ {
2025+ KEY *key=table->key_info+i;
2026+ if (!key->rec_per_key)
2027+ continue;
2028+ if (key->algorithm != HA_KEY_ALG_BTREE)
2029+ {
2030+ if (key->flags & HA_NOSAME)
2031+ key->rec_per_key[key->key_parts-1]= 1;
2032+ else
2033+ {
2034+ unsigned vertices= graph->vertices_count();
2035+ unsigned edges= graph->edges_count();
2036+ uint no_records= vertices ? 2 * (edges + vertices) / vertices : 2;
2037+ if (no_records < 2)
2038+ no_records= 2;
2039+ key->rec_per_key[key->key_parts-1]= no_records;
2040+ }
2041+ }
2042+ }
2043+ records_changed= 0;
2044+ /* At the end of update_key_stats() we can proudly claim they are OK. */
2045+ key_stat_version= share->key_stat_version;
2046+}
2047+
2048+
2049+int ha_oqgraph::write_row(unsigned char *buf)
2050+{
2051+ int res= oqgraph::MISC_FAIL;
2052+ Field ** const field= table->field;
2053+ STATISTIC_INCREMENT(ha_write_count);
2054+
2055+ my_bitmap_map *old_map= table->use_all_columns(table->read_set);
2056+ ptrdiff_t ptrdiff= buf - table->record[0];
2057+
2058+ if (ptrdiff)
2059+ {
2060+ field[1]->MOVE(ptrdiff);
2061+ field[2]->MOVE(ptrdiff);
2062+ field[3]->MOVE(ptrdiff);
2063+ }
2064+
2065+ if (!field[1]->is_null() && !field[2]->is_null())
2066+ {
2067+ VertexID orig_id= (VertexID) field[1]->val_int();
2068+ VertexID dest_id= (VertexID) field[2]->val_int();
2069+ EdgeWeight weight= 1;
2070+
2071+ if (!field[3]->is_null())
2072+ weight= (EdgeWeight) field[3]->val_real();
2073+
2074+ if (!(res= graph->insert_edge(orig_id, dest_id, weight, replace_dups)))
2075+ {
2076+ ++records_changed;
2077+ share->records++;
2078+ }
2079+ if (res == oqgraph::DUPLICATE_EDGE && ignore_dups && !insert_dups)
2080+ res= oqgraph::OK;
2081+ }
2082+
2083+ if (ptrdiff)
2084+ {
2085+ field[1]->MOVE(-ptrdiff);
2086+ field[2]->MOVE(-ptrdiff);
2087+ field[3]->MOVE(-ptrdiff);
2088+ }
2089+ table->restore_column_map(old_map);
2090+
2091+ if (!res && records_changed*OQGRAPH_STATS_UPDATE_THRESHOLD > share->records)
2092+ {
2093+ /*
2094+ We can perform this safely since only one writer at the time is
2095+ allowed on the table.
2096+ */
2097+ share->key_stat_version++;
2098+ }
2099+
2100+ return error_code(res);
2101+}
2102+
2103+int ha_oqgraph::update_row(const unsigned char * old, unsigned char * buf)
2104+{
2105+ int res= oqgraph::MISC_FAIL;
2106+ VertexID orig_id, dest_id;
2107+ EdgeWeight weight= 1;
2108+ Field **field= table->field;
2109+ STATISTIC_INCREMENT(ha_update_count);
2110+
2111+ my_bitmap_map *old_map= table->use_all_columns(table->read_set);
2112+ ptrdiff_t ptrdiff= buf - table->record[0];
2113+
2114+ if (ptrdiff)
2115+ {
2116+ field[0]->MOVE(ptrdiff);
2117+ field[1]->MOVE(ptrdiff);
2118+ field[2]->MOVE(ptrdiff);
2119+ field[3]->MOVE(ptrdiff);
2120+ }
2121+
2122+ if (inited == INDEX || inited == RND)
2123+ {
2124+ VertexID *origp= 0, *destp= 0;
2125+ EdgeWeight *weightp= 0;
2126+ if (!field[1]->is_null())
2127+ *(origp= &orig_id)= (VertexID) field[1]->val_int();
2128+ if (!field[2]->is_null())
2129+ *(destp= &dest_id)= (VertexID) field[2]->val_int();
2130+ if (!field[3]->is_null())
2131+ *(weightp= &weight)= (EdgeWeight) field[3]->val_real();
2132+
2133+ ptrdiff_t ptrdiff2= old - buf;
2134+
2135+ field[0]->MOVE(ptrdiff2);
2136+ field[1]->MOVE(ptrdiff2);
2137+ field[2]->MOVE(ptrdiff2);
2138+ field[3]->MOVE(ptrdiff2);
2139+
2140+ if (field[0]->is_null())
2141+ {
2142+ if (!origp == field[1]->is_null() &&
2143+ *origp == (VertexID) field[1]->val_int())
2144+ origp= 0;
2145+ if (!destp == field[2]->is_null() &&
2146+ *destp == (VertexID) field[2]->val_int())
2147+ origp= 0;
2148+ if (!weightp == field[3]->is_null() &&
2149+ *weightp == (VertexID) field[3]->val_real())
2150+ weightp= 0;
2151+
2152+ if (!(res= graph->modify_edge(oqgraph::current_row(),
2153+ origp, destp, weightp, replace_dups)))
2154+ ++records_changed;
2155+ else if (ignore_dups && res == oqgraph::DUPLICATE_EDGE)
2156+ res= oqgraph::OK;
2157+ }
2158+
2159+ field[0]->MOVE(-ptrdiff2);
2160+ field[1]->MOVE(-ptrdiff2);
2161+ field[2]->MOVE(-ptrdiff2);
2162+ field[3]->MOVE(-ptrdiff2);
2163+ }
2164+
2165+ if (ptrdiff)
2166+ {
2167+ field[0]->MOVE(-ptrdiff);
2168+ field[1]->MOVE(-ptrdiff);
2169+ field[2]->MOVE(-ptrdiff);
2170+ field[3]->MOVE(-ptrdiff);
2171+ }
2172+ table->restore_column_map(old_map);
2173+
2174+ if (!res && records_changed*OQGRAPH_STATS_UPDATE_THRESHOLD > share->records)
2175+ {
2176+ /*
2177+ We can perform this safely since only one writer at the time is
2178+ allowed on the table.
2179+ */
2180+ share->key_stat_version++;
2181+ }
2182+ return error_code(res);
2183+}
2184+
2185+int ha_oqgraph::delete_row(const unsigned char * buf)
2186+{
2187+ int res= oqgraph::EDGE_NOT_FOUND;
2188+ Field **field= table->field;
2189+ STATISTIC_INCREMENT(ha_delete_count);
2190+
2191+ if (inited == INDEX || inited == RND)
2192+ {
2193+ if ((res= graph->delete_edge(oqgraph::current_row())) == oqgraph::OK)
2194+ {
2195+ ++records_changed;
2196+ share->records--;
2197+ }
2198+ }
2199+ if (res != oqgraph::OK)
2200+ {
2201+ my_bitmap_map *old_map= table->use_all_columns(table->read_set);
2202+ ptrdiff_t ptrdiff= buf - table->record[0];
2203+
2204+ if (ptrdiff)
2205+ {
2206+ field[0]->MOVE(ptrdiff);
2207+ field[1]->MOVE(ptrdiff);
2208+ field[2]->MOVE(ptrdiff);
2209+ }
2210+
2211+ if (field[0]->is_null() && !field[1]->is_null() && !field[2]->is_null())
2212+ {
2213+ VertexID orig_id= (VertexID) field[1]->val_int();
2214+ VertexID dest_id= (VertexID) field[2]->val_int();
2215+
2216+ if ((res= graph->delete_edge(orig_id, dest_id)) == oqgraph::OK)
2217+ {
2218+ ++records_changed;
2219+ share->records--;
2220+ }
2221+ }
2222+
2223+ if (ptrdiff)
2224+ {
2225+ field[0]->MOVE(-ptrdiff);
2226+ field[1]->MOVE(-ptrdiff);
2227+ field[2]->MOVE(-ptrdiff);
2228+ }
2229+ table->restore_column_map(old_map);
2230+ }
2231+
2232+ if (!res && table->s->tmp_table == NO_TMP_TABLE &&
2233+ records_changed*OQGRAPH_STATS_UPDATE_THRESHOLD > share->records)
2234+ {
2235+ /*
2236+ We can perform this safely since only one writer at the time is
2237+ allowed on the table.
2238+ */
2239+ share->key_stat_version++;
2240+ }
2241+ return error_code(res);
2242+}
2243+
2244+int ha_oqgraph::index_read(unsigned char * buf, const unsigned char * key, uint key_len,
2245+ enum ha_rkey_function find_flag)
2246+{
2247+ assert(inited==INDEX);
2248+ return index_read_idx(buf, active_index, key, key_len, find_flag);
2249+}
2250+
2251+int ha_oqgraph::index_next_same(unsigned char *buf, const unsigned char *, uint)
2252+{
2253+ int res;
2254+ open_query::row row;
2255+ assert(inited==INDEX);
2256+ STATISTIC_INCREMENT(ha_read_key_count);
2257+ if (!(res= graph->fetch_row(row)))
2258+ res= fill_record(buf, row);
2259+ table->status= res ? STATUS_NOT_FOUND : 0;
2260+ return error_code(res);
2261+}
2262+
2263+int ha_oqgraph::index_read_idx(unsigned char * buf,
2264+ uint32_t index,
2265+ const unsigned char * key,
2266+ uint32_t key_len, enum ha_rkey_function)
2267+{
2268+ Field **field= table->field;
2269+ KEY *key_info= table->key_info + index;
2270+ int res;
2271+ VertexID orig_id, dest_id;
2272+ int latch;
2273+ VertexID *orig_idp=0, *dest_idp=0;
2274+ int *latchp=0;
2275+ open_query::row row;
2276+ STATISTIC_INCREMENT(ha_read_key_count);
2277+
2278+ memcpy(buf, table->s->default_values, table->s->reclength);
2279+ key_restore(buf, (unsigned char*) key, key_info, key_len);
2280+
2281+ my_bitmap_map *old_map= table->use_all_columns(table->read_set);
2282+ ptrdiff_t ptrdiff= buf - table->record[0];
2283+
2284+ if (ptrdiff)
2285+ {
2286+ field[0]->MOVE(ptrdiff);
2287+ field[1]->MOVE(ptrdiff);
2288+ field[2]->MOVE(ptrdiff);
2289+ }
2290+
2291+ if (!field[0]->is_null())
2292+ {
2293+ latch= (int) field[0]->val_int();
2294+ latchp= &latch;
2295+ }
2296+
2297+ if (!field[1]->is_null())
2298+ {
2299+ orig_id= (VertexID) field[1]->val_int();
2300+ orig_idp= &orig_id;
2301+ }
2302+
2303+ if (!field[2]->is_null())
2304+ {
2305+ dest_id= (VertexID) field[2]->val_int();
2306+ dest_idp= &dest_id;
2307+ }
2308+
2309+ if (ptrdiff)
2310+ {
2311+ field[0]->MOVE(-ptrdiff);
2312+ field[1]->MOVE(-ptrdiff);
2313+ field[2]->MOVE(-ptrdiff);
2314+ }
2315+ table->restore_column_map(old_map);
2316+
2317+ res= graph->search(latchp, orig_idp, dest_idp);
2318+
2319+ if (!res && !(res= graph->fetch_row(row)))
2320+ res= fill_record(buf, row);
2321+ table->status = res ? STATUS_NOT_FOUND : 0;
2322+ return error_code(res);
2323+}
2324+
2325+int ha_oqgraph::fill_record(unsigned char *record, const open_query::row &row)
2326+{
2327+ Field **field= table->field;
2328+
2329+ memcpy(record, table->s->default_values, table->s->reclength);
2330+
2331+ my_bitmap_map *old_map= table->use_all_columns(table->write_set);
2332+ ptrdiff_t ptrdiff= record - table->record[0];
2333+
2334+ if (ptrdiff)
2335+ {
2336+ field[0]->MOVE(ptrdiff);
2337+ field[1]->MOVE(ptrdiff);
2338+ field[2]->MOVE(ptrdiff);
2339+ field[3]->MOVE(ptrdiff);
2340+ field[4]->MOVE(ptrdiff);
2341+ field[5]->MOVE(ptrdiff);
2342+ }
2343+
2344+ table->restoreRecordAsDefault();
2345+ table->setWriteSet(0);
2346+ table->setWriteSet(1);
2347+ table->setWriteSet(2);
2348+ table->setWriteSet(3);
2349+ table->setWriteSet(4);
2350+ table->setWriteSet(5);
2351+
2352+ // just each field specifically, no sense iterating
2353+ if (row.latch_indicator)
2354+ {
2355+ field[0]->set_notnull();
2356+ field[0]->store((uint64_t) row.latch);
2357+ }
2358+
2359+ if (row.orig_indicator)
2360+ {
2361+ field[1]->set_notnull();
2362+ field[1]->store((uint64_t) row.orig);
2363+ }
2364+
2365+ if (row.dest_indicator)
2366+ {
2367+ field[2]->set_notnull();
2368+ field[2]->store((uint64_t) row.dest);
2369+ }
2370+
2371+ if (row.weight_indicator)
2372+ {
2373+ field[3]->set_notnull();
2374+ field[3]->store((double) row.weight);
2375+ }
2376+
2377+ if (row.seq_indicator)
2378+ {
2379+ field[4]->set_notnull();
2380+ field[4]->store((uint64_t) row.seq);
2381+ }
2382+
2383+ if (row.link_indicator)
2384+ {
2385+ field[5]->set_notnull();
2386+ field[5]->store((uint64_t) row.link);
2387+ }
2388+
2389+ if (ptrdiff)
2390+ {
2391+ field[0]->MOVE(-ptrdiff);
2392+ field[1]->MOVE(-ptrdiff);
2393+ field[2]->MOVE(-ptrdiff);
2394+ field[3]->MOVE(-ptrdiff);
2395+ field[4]->MOVE(-ptrdiff);
2396+ field[5]->MOVE(-ptrdiff);
2397+ }
2398+ table->restore_column_map(old_map);
2399+
2400+ return 0;
2401+}
2402+
2403+int ha_oqgraph::rnd_init(bool scan)
2404+{
2405+ return error_code(graph->random(scan));
2406+}
2407+
2408+int ha_oqgraph::rnd_next(unsigned char *buf)
2409+{
2410+ int res;
2411+ open_query::row row;
2412+ STATISTIC_INCREMENT(ha_read_rnd_next_count);
2413+ if (!(res= graph->fetch_row(row)))
2414+ res= fill_record(buf, row);
2415+ table->status= res ? STATUS_NOT_FOUND: 0;
2416+ return error_code(res);
2417+}
2418+
2419+int ha_oqgraph::rnd_pos(unsigned char * buf, unsigned char *pos)
2420+{
2421+ int res;
2422+ open_query::row row;
2423+ STATISTIC_INCREMENT(ha_read_rnd_count);
2424+ if (!(res= graph->fetch_row(row, pos)))
2425+ res= fill_record(buf, row);
2426+ table->status=res ? STATUS_NOT_FOUND: 0;
2427+ return error_code(res);
2428+}
2429+
2430+void ha_oqgraph::position(const unsigned char *)
2431+{
2432+ graph->row_ref((void*) ref); // Ref is aligned
2433+}
2434+
2435+int ha_oqgraph::cmp_ref(const unsigned char *ref1, const unsigned char *ref2)
2436+{
2437+ return memcmp(ref1, ref2, oqgraph::sizeof_ref);
2438+}
2439+
2440+int ha_oqgraph::info(uint32_t)
2441+{
2442+ RECORDS= graph->vertices_count() + graph->edges_count();
2443+#if 0
2444+ records= hp_info.records;
2445+ deleted= hp_info.deleted;
2446+ errkey= hp_info.errkey;
2447+ mean_rec_length= hp_info.reclength;
2448+ data_file_length= hp_info.data_length;
2449+ index_file_length= hp_info.index_length;
2450+ max_data_file_length= hp_info.max_records* hp_info.reclength;
2451+ delete_length= hp_info.deleted * hp_info.reclength;
2452+#endif
2453+ /*
2454+ If info() is called for the first time after open(), we will still
2455+ have to update the key statistics. Hoping that a table lock is now
2456+ in place.
2457+ */
2458+ if (key_stat_version != share->key_stat_version)
2459+ update_key_stats();
2460+ return 0;
2461+}
2462+
2463+int ha_oqgraph::extra(enum ha_extra_function operation)
2464+{
2465+ switch (operation)
2466+ {
2467+ case HA_EXTRA_IGNORE_DUP_KEY:
2468+ ignore_dups= true;
2469+ break;
2470+ case HA_EXTRA_NO_IGNORE_DUP_KEY:
2471+ ignore_dups= false;
2472+ insert_dups= false;
2473+ break;
2474+ case HA_EXTRA_WRITE_CAN_REPLACE:
2475+ replace_dups= true;
2476+ break;
2477+ case HA_EXTRA_WRITE_CANNOT_REPLACE:
2478+ replace_dups= false;
2479+ break;
2480+ case HA_EXTRA_INSERT_WITH_UPDATE:
2481+ insert_dups= true;
2482+ break;
2483+ default:
2484+ break;
2485+ }
2486+ return 0;
2487+}
2488+
2489+int ha_oqgraph::delete_all_rows()
2490+{
2491+ int res;
2492+ if (!(res= graph->delete_all()))
2493+ {
2494+ share->records= 0;
2495+ }
2496+
2497+ if (!res && table->s->tmp_table == NO_TMP_TABLE)
2498+ {
2499+ /*
2500+ We can perform this safely since only one writer at the time is
2501+ allowed on the table.
2502+ */
2503+ share->key_stat_version++;
2504+ }
2505+ return error_code(res);
2506+}
2507+
2508+int ha_oqgraph::external_lock(Session *, int)
2509+{
2510+ return 0; // No external locking
2511+}
2512+
2513+
2514+THR_LOCK_DATA **ha_oqgraph::store_lock(Session *,
2515+ THR_LOCK_DATA **to,
2516+ enum thr_lock_type lock_type)
2517+{
2518+ if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
2519+ lock.type=lock_type;
2520+ *to++= &lock;
2521+ return to;
2522+}
2523+
2524+/*
2525+ We have to ignore ENOENT entries as the HEAP table is created on open and
2526+ not when doing a CREATE on the table.
2527+*/
2528+
2529+int OqgraphEngine::deleteTableImplementation(Session *,
2530+ const string table_name)
2531+{
2532+ int res= 0;
2533+ OQGRAPH_INFO *share= NULL;
2534+ OpenTables &open_tables= OpenTables::singleton();
2535+ if ((share= open_tables.getShare(table_name.c_str())))
2536+ {
2537+ open_tables.freeShare();
2538+ }
2539+ return error_code(res);
2540+}
2541+
2542+int OqgraphEngine::renameTableImplementation(Session *,
2543+ const char * from,
2544+ const char * to)
2545+{
2546+ OpenTables &open_tables= OpenTables::singleton();
2547+ if (OQGRAPH_INFO *share= open_tables.getShare(from))
2548+ {
2549+ strcpy(share->name, to);
2550+ open_tables.updateShare(share);
2551+ }
2552+ return 0;
2553+}
2554+
2555+
2556+ha_rows ha_oqgraph::records_in_range(uint32_t inx,
2557+ key_range *min_key,
2558+ key_range *max_key)
2559+{
2560+ KEY *key=table->key_info+inx;
2561+ //if (key->algorithm == HA_KEY_ALG_BTREE)
2562+ // return btree_records_in_range(file, inx, min_key, max_key);
2563+
2564+ if (!min_key || !max_key ||
2565+ min_key->length != max_key->length ||
2566+ min_key->length < key->key_length - key->key_part[2].store_length ||
2567+ min_key->flag != HA_READ_KEY_EXACT ||
2568+ max_key->flag != HA_READ_AFTER_KEY)
2569+ {
2570+ if (min_key->length == key->key_part[0].store_length)
2571+ {
2572+ // If latch is not null and equals 0, return # nodes
2573+ //assert(key->key_part[0].store_length == 3);
2574+ if (key->key_part[0].null_bit && !min_key->key[0] &&
2575+ !min_key->key[1] && !min_key->key[2])
2576+ return graph->vertices_count();
2577+ }
2578+ return HA_POS_ERROR; // Can only use exact keys
2579+ }
2580+
2581+ if (RECORDS <= 1)
2582+ return RECORDS;
2583+
2584+ /* Assert that info() did run. We need current statistics here. */
2585+ assert(key_stat_version == share->key_stat_version);
2586+ ha_rows result= key->rec_per_key[key->key_parts-1];
2587+
2588+ return result;
2589+}
2590+
2591+
2592+int OqgraphEngine::createTableImplementation(Session *,
2593+ const char *table_name,
2594+ Table *in_table,
2595+ HA_CREATE_INFO *,
2596+ drizzled::message::Table *)
2597+{
2598+ int res = -1;
2599+ OQGRAPH_INFO *share= NULL;
2600+
2601+ OpenTables &open_tables= OpenTables::singleton();
2602+ share= open_tables.getShare(table_name);
2603+ if (! share)
2604+ {
2605+ res= -1;
2606+ }
2607+ else
2608+ {
2609+ res= oqgraph_check_table_structure(in_table);
2610+ }
2611+
2612+ return error_code(res);
2613+}
2614+
2615+
2616+drizzle_declare_plugin(oqgraph)
2617+{
2618+ "OQGRAPH",
2619+ "2.0", /* Version: 2.0 */
2620+ "Arjen Lentz & Antony T Curtis, Open Query",
2621+ "Open Query Graph Computation Engine, stored in memory (http://openquery.com/graph)",
2622+ PLUGIN_LICENSE_GPL,
2623+ oqgraph_init, /* Plugin Init */
2624+ oqgraph_fini, /* Plugin Deinit */
2625+ NULL, /* status variables */
2626+ NULL, /* system variables */
2627+ NULL /* config options */
2628+}
2629+drizzle_declare_plugin_end;
2630
2631=== added file 'oqgraph/ha_oqgraph.h'
2632--- oqgraph/ha_oqgraph.h 1970-01-01 00:00:00 +0000
2633+++ oqgraph/ha_oqgraph.h 2009-10-25 07:55:23 +0000
2634@@ -0,0 +1,118 @@
2635+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
2636+ Portions of this file copyright (C) 2000-2006 MySQL AB
2637+
2638+ This program is free software; you can redistribute it and/or modify
2639+ it under the terms of the GNU General Public License as published by
2640+ the Free Software Foundation; version 2 of the License.
2641+
2642+ This program is distributed in the hope that it will be useful,
2643+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2644+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2645+ GNU General Public License for more details.
2646+
2647+ You should have received a copy of the GNU General Public License
2648+ along with this program; if not, write to the Free Software
2649+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
2650+
2651+/* ======================================================================
2652+ Open Query Graph Computation Engine, based on a concept by Arjen Lentz
2653+ Mk.II implementation by Antony Curtis & Arjen Lentz
2654+ For more information, documentation, support, enhancement engineering,
2655+ and non-GPL licensing, see http://openquery.com/graph
2656+ or contact graph@openquery.com
2657+ For packaged binaries, see http://ourdelta.org
2658+ ======================================================================
2659+*/
2660+
2661+#ifndef OQGRAPH_HANDLER_HA_OQGRAPH_H
2662+#define OQGRAPH_HANDLER_HA_OQGRAPH_H
2663+
2664+#include "drizzled/cursor.h"
2665+#include "graphcore.h"
2666+
2667+struct oqgraph_info_st
2668+{
2669+ THR_LOCK lock;
2670+ open_query::oqgraph_share *graph;
2671+ uint use_count;
2672+ uint key_stat_version;
2673+ uint records;
2674+ bool dropped;
2675+ char name[FN_REFLEN+1];
2676+};
2677+
2678+typedef struct oqgraph_info_st OQGRAPH_INFO;
2679+
2680+namespace open_query
2681+{
2682+ struct row;
2683+ class oqgraph;
2684+}
2685+
2686+/* class for the the Open Query Graph cursor */
2687+
2688+class ha_oqgraph: public Cursor
2689+{
2690+ OQGRAPH_INFO *share;
2691+ open_query::oqgraph *graph;
2692+ THR_LOCK_DATA lock;
2693+ /* number of records changed since last statistics update */
2694+ uint records_changed;
2695+ uint key_stat_version;
2696+ bool replace_dups, ignore_dups, insert_dups;
2697+
2698+ int fill_record(unsigned char*, const open_query::row&);
2699+
2700+public:
2701+ ha_oqgraph(drizzled::plugin::StorageEngine *engine,
2702+ TableShare *table_arg);
2703+ ~ha_oqgraph() {}
2704+
2705+ uint64_t table_flags() const;
2706+ const char *table_type() const
2707+ {
2708+ return "OQGRAPH";
2709+ }
2710+ const char *index_type(uint32_t)
2711+ {
2712+ return "HASH";
2713+ }
2714+ /* Rows also use a fixed-size format */
2715+ enum row_type get_row_type() const { return ROW_TYPE_FIXED; }
2716+ uint32_t index_flags(uint32_t inx, uint32_t part, bool all_parts) const;
2717+ uint32_t max_supported_keys() const { return MAX_KEY; }
2718+ uint32_t max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
2719+ double scan_time() { return (double) 1000000000; }
2720+ double read_time(uint32_t, uint32_t, ha_rows)
2721+ { return 1; }
2722+
2723+ int open(const char *name, int mode, uint32_t test_if_locked);
2724+ int close(void);
2725+ int write_row(unsigned char * buf);
2726+ int update_row(const unsigned char * old_data, unsigned char * new_data);
2727+ int delete_row(const unsigned char * buf);
2728+ int index_read(unsigned char * buf, const unsigned char * key,
2729+ uint32_t key_len, enum ha_rkey_function find_flag);
2730+ int index_read_idx(unsigned char * buf, uint32_t idx, const unsigned char * key,
2731+ uint32_t key_len, enum ha_rkey_function find_flag);
2732+ int index_next_same(unsigned char * buf,
2733+ const unsigned char * key,
2734+ uint32_t key_len);
2735+ int rnd_init(bool scan);
2736+ int rnd_next(unsigned char *buf);
2737+ int rnd_pos(unsigned char * buf, unsigned char *pos);
2738+ void position(const unsigned char *record);
2739+ int info(uint32_t);
2740+ int extra(enum ha_extra_function operation);
2741+ int external_lock(Session *session, int lock_type);
2742+ int delete_all_rows(void);
2743+ ha_rows records_in_range(uint32_t inx, key_range *min_key, key_range *max_key);
2744+
2745+ THR_LOCK_DATA **store_lock(Session *session, THR_LOCK_DATA **to,
2746+ enum thr_lock_type lock_type);
2747+ int cmp_ref(const unsigned char *ref1, const unsigned char *ref2);
2748+private:
2749+ void update_key_stats();
2750+};
2751+
2752+#endif /* OQGRAPH_HANDLER_OQGRAPH_H */
2753
2754=== added file 'oqgraph/open_tables.cc'
2755--- oqgraph/open_tables.cc 1970-01-01 00:00:00 +0000
2756+++ oqgraph/open_tables.cc 2009-10-25 07:55:23 +0000
2757@@ -0,0 +1,91 @@
2758+/*
2759+ * Copyright (C) 2009 Sun Microsystems
2760+ *
2761+ * This program is free software; you can redistribute it and/or modify
2762+ * it under the terms of the GNU General Public License as published by
2763+ * the Free Software Foundation; either version 2 of the License, or
2764+ * (at your option) any later version.
2765+ *
2766+ * This program is distributed in the hope that it will be useful,
2767+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2768+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2769+ * GNU General Public License for more details.
2770+ *
2771+ * You should have received a copy of the GNU General Public License
2772+ * along with this program; if not, write to the Free Software
2773+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2774+ */
2775+
2776+#include <drizzled/server_includes.h>
2777+#include "ha_oqgraph.h"
2778+#include "graphcore.h"
2779+#include "open_tables.h"
2780+
2781+#include <string>
2782+#include <map>
2783+
2784+using namespace std;
2785+using namespace open_query;
2786+using namespace drizzled;
2787+
2788+OQGRAPH_INFO *OpenTables::getShare(const char *name)
2789+{
2790+ map<const string, OQGRAPH_INFO *>::iterator it;
2791+ pthread_mutex_lock(&mutex);
2792+
2793+ it= open_tables.find(name);
2794+ if (it != open_tables.end())
2795+ {
2796+ share= (*it).second;
2797+ }
2798+ else
2799+ {
2800+ share= NULL;
2801+ }
2802+
2803+ if (! share)
2804+ {
2805+ share= new(std::nothrow) OQGRAPH_INFO();
2806+ if (! share)
2807+ {
2808+ pthread_mutex_unlock(&mutex);
2809+ return NULL;
2810+ }
2811+ share->use_count= 0;
2812+ share->key_stat_version= 0;
2813+ share->records= 0;
2814+ share->dropped= 0;
2815+ strcpy(share->name, name);
2816+ share->graph= oqgraph::create();
2817+ if (! share->graph)
2818+ {
2819+ pthread_mutex_unlock(&mutex);
2820+ return NULL;
2821+ }
2822+ open_tables[name]= share;
2823+ thr_lock_init(&share->lock);
2824+ }
2825+ share->use_count++;
2826+ pthread_mutex_unlock(&mutex);
2827+
2828+ return share;
2829+}
2830+
2831+void OpenTables::freeShare()
2832+{
2833+ pthread_mutex_lock(&mutex);
2834+ share->use_count--;
2835+ if (share->use_count == 0)
2836+ {
2837+ open_tables.erase(share->name);
2838+ oqgraph::free(share->graph);
2839+ }
2840+ pthread_mutex_unlock(&mutex);
2841+}
2842+
2843+void OpenTables::updateShare(OQGRAPH_INFO *in_share)
2844+{
2845+ pthread_mutex_lock(&mutex);
2846+ open_tables[in_share->name]= in_share;
2847+ pthread_mutex_unlock(&mutex);
2848+}
2849
2850=== added file 'oqgraph/open_tables.h'
2851--- oqgraph/open_tables.h 1970-01-01 00:00:00 +0000
2852+++ oqgraph/open_tables.h 2009-10-25 07:55:23 +0000
2853@@ -0,0 +1,93 @@
2854+/* Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
2855+ Portions of this file copyright (C) 2000-2006 MySQL AB
2856+
2857+ This program is free software; you can redistribute it and/or modify
2858+ it under the terms of the GNU General Public License as published by
2859+ the Free Software Foundation; version 2 of the License.
2860+
2861+ This program is distributed in the hope that it will be useful,
2862+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2863+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2864+ GNU General Public License for more details.
2865+
2866+ You should have received a copy of the GNU General Public License
2867+ along with this program; if not, write to the Free Software
2868+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
2869+
2870+/**
2871+ * @file
2872+ *
2873+ * Defines a class for how open tables will be tracked for this storage
2874+ * engine.
2875+ */
2876+
2877+#ifndef OQGRAPH_OPEN_TABLES_H
2878+#define OQGRAPH_OPEN_TABLES_H
2879+
2880+#include "ha_oqgraph.h"
2881+
2882+#include <string>
2883+#include <vector>
2884+#include <map>
2885+
2886+/**
2887+ * @class OpenTables
2888+ *
2889+ * Class which tracks all the open tables for the storage engine.
2890+ * Encapsulating this functionality in a class will make it easier for us to
2891+ * change things such as whether a std::map or HASH is used to lookup the
2892+ * open tables.
2893+ */
2894+class OpenTables
2895+{
2896+public:
2897+
2898+ static OpenTables &singleton()
2899+ {
2900+ static OpenTables open_tabs;
2901+ return open_tabs;
2902+ }
2903+
2904+ /**
2905+ * Retrieve a share from the structure used to main the list of open
2906+ * shares. We do a lookup by name.
2907+ *
2908+ * @param[in] name name to lookup
2909+ * @return pointer to the appropriate table share
2910+ */
2911+ OQGRAPH_INFO *getShare(const char *name);
2912+
2913+ /**
2914+ * Erase a share from the structure used to maintain the list of shares.
2915+ */
2916+ void freeShare();
2917+
2918+ void updateShare(OQGRAPH_INFO *share);
2919+
2920+private:
2921+
2922+ pthread_mutex_t mutex;
2923+
2924+ std::map<const std::string, OQGRAPH_INFO *>
2925+ open_tables;
2926+
2927+ OQGRAPH_INFO *share;
2928+
2929+ OpenTables()
2930+ :
2931+ mutex(),
2932+ open_tables(),
2933+ share(NULL)
2934+ {
2935+ pthread_mutex_init(&mutex, MY_MUTEX_INIT_FAST);
2936+ }
2937+
2938+ ~OpenTables()
2939+ {
2940+ pthread_mutex_destroy(&mutex);
2941+ }
2942+
2943+ OpenTables(const OpenTables&);
2944+};
2945+
2946+#endif /* OQGRAPH_OPEN_TABLES_H */
2947
2948=== added file 'oqgraph/oqgraph_config.h.in'
2949--- oqgraph/oqgraph_config.h.in 1970-01-01 00:00:00 +0000
2950+++ oqgraph/oqgraph_config.h.in 2009-10-25 07:55:23 +0000
2951@@ -0,0 +1,73 @@
2952+/* src/oqgraph_config.h.in. Generated from configure.in by autoheader. */
2953+
2954+/* Define to 1 if you have the <dlfcn.h> header file. */
2955+#undef HAVE_DLFCN_H
2956+
2957+/* Enables DTRACE Support */
2958+#undef HAVE_DTRACE
2959+
2960+/* Define to 1 if you have the <inttypes.h> header file. */
2961+#undef HAVE_INTTYPES_H
2962+
2963+/* Define to 1 if you have the <limits.h> header file. */
2964+#undef HAVE_LIMITS_H
2965+
2966+/* Define to 1 if you have the <memory.h> header file. */
2967+#undef HAVE_MEMORY_H
2968+
2969+/* Define to 1 if you have the <stdint.h> header file. */
2970+#undef HAVE_STDINT_H
2971+
2972+/* Define to 1 if you have the <stdlib.h> header file. */
2973+#undef HAVE_STDLIB_H
2974+
2975+/* Define to 1 if you have the <strings.h> header file. */
2976+#undef HAVE_STRINGS_H
2977+
2978+/* Define to 1 if you have the <string.h> header file. */
2979+#undef HAVE_STRING_H
2980+
2981+/* Define to 1 if you have the <syslimits.h> header file. */
2982+#undef HAVE_SYSLIMITS_H
2983+
2984+/* Define to 1 if you have the <sys/stat.h> header file. */
2985+#undef HAVE_SYS_STAT_H
2986+
2987+/* Define to 1 if you have the <sys/types.h> header file. */
2988+#undef HAVE_SYS_TYPES_H
2989+
2990+/* Define to 1 if you have the <unistd.h> header file. */
2991+#undef HAVE_UNISTD_H
2992+
2993+/* Source directory for MySQL */
2994+#undef MYSQL_SRC
2995+
2996+/* Name of package */
2997+#undef PACKAGE
2998+
2999+/* Define to the address where bug reports for this package should be sent. */
3000+#undef PACKAGE_BUGREPORT
3001+
3002+/* Define to the full name of this package. */
3003+#undef PACKAGE_NAME
3004+
3005+/* Define to the full name and version of this package. */
3006+#undef PACKAGE_STRING
3007+
3008+/* Define to the one symbol short name of this package. */
3009+#undef PACKAGE_TARNAME
3010+
3011+/* Define to the version of this package. */
3012+#undef PACKAGE_VERSION
3013+
3014+/* Define to 1 if you have the ANSI C header files. */
3015+#undef STDC_HEADERS
3016+
3017+/* Version number of package */
3018+#undef VERSION
3019+
3020+/* Define to empty if `const' does not conform to ANSI C. */
3021+#undef const
3022+
3023+/* Define to `unsigned int' if <sys/types.h> does not define. */
3024+#undef size_t
3025
3026=== added file 'oqgraph/oqgraph_probes.d'
3027--- oqgraph/oqgraph_probes.d 1970-01-01 00:00:00 +0000
3028+++ oqgraph/oqgraph_probes.d 2009-10-25 07:55:23 +0000
3029@@ -0,0 +1,19 @@
3030+/* Copyright (C) 2004-2005 MySQL AB
3031+
3032+ This program is free software; you can redistribute it and/or modify
3033+ it under the terms of the GNU General Public License as published by
3034+ the Free Software Foundation; version 2 of the License.
3035+
3036+ This program is distributed in the hope that it will be useful,
3037+ but WITHOUT ANY WARRANTY; without even the implied warranty of
3038+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3039+ GNU General Public License for more details.
3040+
3041+ You should have received a copy of the GNU General Public License
3042+ along with this program; if not, write to the Free Software
3043+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
3044+
3045+provider oqgraph {
3046+ probe open();
3047+ probe close();
3048+};
3049
3050=== added file 'oqgraph/oqgraph_probes.h'
3051--- oqgraph/oqgraph_probes.h 1970-01-01 00:00:00 +0000
3052+++ oqgraph/oqgraph_probes.h 2009-10-25 07:55:23 +0000
3053@@ -0,0 +1,45 @@
3054+/*
3055+ * Generated by dtrace(1M).
3056+ */
3057+
3058+#ifndef _OQGRAPH_PROBES_H
3059+#define _OQGRAPH_PROBES_H
3060+
3061+
3062+
3063+#ifdef __cplusplus
3064+extern "C" {
3065+#endif
3066+
3067+#if _DTRACE_VERSION
3068+
3069+#define OQGRAPH_CLOSE() \
3070+ __dtrace_oqgraph___close()
3071+#define OQGRAPH_CLOSE_ENABLED() \
3072+ __dtraceenabled_oqgraph___close()
3073+#define OQGRAPH_OPEN() \
3074+ __dtrace_oqgraph___open()
3075+#define OQGRAPH_OPEN_ENABLED() \
3076+ __dtraceenabled_oqgraph___open()
3077+
3078+
3079+extern void __dtrace_oqgraph___close(void);
3080+extern int __dtraceenabled_oqgraph___close(void);
3081+extern void __dtrace_oqgraph___open(void);
3082+extern int __dtraceenabled_oqgraph___open(void);
3083+
3084+#else
3085+
3086+#define OQGRAPH_CLOSE()
3087+#define OQGRAPH_CLOSE_ENABLED() (0)
3088+#define OQGRAPH_OPEN()
3089+#define OQGRAPH_OPEN_ENABLED() (0)
3090+
3091+#endif
3092+
3093+
3094+#ifdef __cplusplus
3095+}
3096+#endif
3097+
3098+#endif /* _OQGRAPH_PROBES_H */
3099
3100=== added file 'oqgraph/plugin.am'
3101--- oqgraph/plugin.am 1970-01-01 00:00:00 +0000
3102+++ oqgraph/plugin.am 2009-10-25 07:55:23 +0000
3103@@ -0,0 +1,67 @@
3104+# Copyright (C) 2007-2009 Arjen G Lentz & Antony T Curtis for Open Query
3105+#
3106+# This program is free software; you can redistribute it and/or modify
3107+# it under the terms of the GNU General Public License as published by
3108+# the Free Software Foundation; version 2 of the License, or
3109+# (at your option) any later version.
3110+#
3111+# This program is distributed in the hope that it will be useful,
3112+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3113+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3114+# GNU General Public License for more details.
3115+#
3116+# You should have received a copy of the GNU General Public License
3117+# along with this program; if not, write to the Free Software
3118+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
3119+
3120+# ======================================================================
3121+# Open Query Graph Computation Engine, based on a concept by Arjen Lentz
3122+# Mk.II implementation by Antony Curtis & Arjen Lentz
3123+# For more information, documentation, support, enhancement engineering,
3124+# and non-GPL licensing, see http://openquery.com/graph
3125+# or contact graph@openquery.com
3126+# For packaged binaries, see http://ourdelta.org
3127+# ======================================================================
3128+
3129+BOOST_CXXFLAGS = -fexceptions -fimplicit-templates
3130+#BOOST_CXXFLAGS+= -g
3131+BOOST_CXXFLAGS+= -O3 -fomit-frame-pointer -fstrict-aliasing
3132+BOOST_CXXFLAGS+= -momit-leaf-frame-pointer -falign-loops
3133+BOOST_CXXFLAGS+= -fvisibility-inlines-hidden
3134+BOOST_CXXFLAGS+= -funroll-loops -fno-trapping-math
3135+
3136+DTRACE = @DTRACE@
3137+DTRACEFLAGS = @DTRACEFLAGS@
3138+DTRACEFILES = .libs/liboqgraph_engine_la-ha_oqgraph.o
3139+
3140+#noinst_PROGRAMS = graphcore_test
3141+
3142+noinst_LTLIBRARIES+= plugin/oqgraph/liboqgraph.la
3143+noinst_HEADERS+= plugin/oqgraph/graphcore.h \
3144+ plugin/oqgraph/graphcore-graph.h \
3145+ plugin/oqgraph/graphcore-types.h \
3146+ plugin/oqgraph/graphstore.h
3147+
3148+#graphcore_test_SOURCES = graphcore-test.cc
3149+#graphcore_test_LDADD = libgraphcore.la
3150+
3151+plugin_oqgraph_liboqgraph_la_SOURCES = plugin/oqgraph/graphcore.cc
3152+plugin_oqgraph_liboqgraph_la_CXXFLAGS = @CXXFLAGS@
3153+#plugin_oqgraph_liboqgraph_la_CXXFLAGS = @CXXFLAGS@ ${BOOST_CXXFLAGS)
3154+plugin_oqgraph_liboqgraph_la_LDFLAGS = -module
3155+# -fimplicit-templates
3156+
3157+if HAVE_DTRACE
3158+ plugin_oqgraph_liboqgraph_la_LIBADD = oqgraph_probes.o
3159+endif
3160+
3161+oqgraph_probes.h: oqgraph_probes.d
3162+ $(DTRACE) $(DTRACEFLAGS) -h -s oqgraph_probes.d
3163+ mv oqgraph_probes.h oqgraph_probes.h.bak
3164+ sed "s/#include <unistd.h>//g" oqgraph_probes.h.bak > oqgraph_probes.h
3165+ rm oqgraph_probes.h.bak
3166+
3167+oqgraph_probes.o:
3168+ $(DTRACE) $(DTRACEFLAGS) -G -s oqgraph_probes.d $(DTRACEFILES)
3169+
3170+# End
3171
3172=== added file 'oqgraph/plugin.ini'
3173--- oqgraph/plugin.ini 1970-01-01 00:00:00 +0000
3174+++ oqgraph/plugin.ini 2009-10-25 07:55:23 +0000
3175@@ -0,0 +1,9 @@
3176+[plugin]
3177+name=oqgraph
3178+title=Graph Storage Engine
3179+description=Computation engine for handling hierarchies and graphs
3180+load_by_default=yes
3181+sources=ha_oqgraph.cc open_tables.cc
3182+headers=ha_oqgraph.h open_tables.h
3183+libs=plugin/oqgraph/liboqgraph.la
3184+#testsuite=oqgraph
3185
3186=== added directory 'oqgraph/tests'
3187=== added directory 'oqgraph/tests/r'
3188=== added file 'oqgraph/tests/r/basic.result'
3189--- oqgraph/tests/r/basic.result 1970-01-01 00:00:00 +0000
3190+++ oqgraph/tests/r/basic.result 2009-10-25 07:55:23 +0000
3191@@ -0,0 +1,33 @@
3192+drop table if exists graph;
3193+Warnings:
3194+Note 1051 Unknown table 'graph'
3195+create table graph (
3196+latch int null,
3197+origid bigint null,
3198+destid bigint null,
3199+weight double null,
3200+seq bigint null,
3201+linkid bigint null,
3202+key (latch, origid, destid) using hash,
3203+key (latch, destid, origid) using hash
3204+) engine=oqgraph;
3205+insert into graph(origid, destid) values (1,2), (2,1);
3206+insert into graph(origid, destid) values (1,3), (3,1);
3207+insert into graph(origid, destid) values (3,4), (4,3);
3208+insert into graph(origid, destid) values (3,5), (5,3);
3209+insert into graph(origid, destid) values (5,6), (6,5);
3210+select linkid from graph where latch = 2 and origid = 1 and weight = 1;
3211+linkid
3212+3
3213+2
3214+select linkid from graph where latch = 2 and origid = 1 and weight = 2;
3215+linkid
3216+5
3217+4
3218+select linkid from graph
3219+where latch = 2 and origid = 1 and (weight = 1 or weight = 2);
3220+linkid
3221+5
3222+4
3223+3
3224+2
3225
3226=== added directory 'oqgraph/tests/t'
3227=== added file 'oqgraph/tests/t/basic.test'
3228--- oqgraph/tests/t/basic.test 1970-01-01 00:00:00 +0000
3229+++ oqgraph/tests/t/basic.test 2009-10-25 07:55:23 +0000
3230@@ -0,0 +1,25 @@
3231+drop table if exists graph;
3232+
3233+create table graph (
3234+latch int null,
3235+origid bigint null,
3236+destid bigint null,
3237+weight double null,
3238+seq bigint null,
3239+linkid bigint null,
3240+key (latch, origid, destid) using hash,
3241+key (latch, destid, origid) using hash
3242+) engine=oqgraph;
3243+
3244+insert into graph(origid, destid) values (1,2), (2,1);
3245+insert into graph(origid, destid) values (1,3), (3,1);
3246+insert into graph(origid, destid) values (3,4), (4,3);
3247+insert into graph(origid, destid) values (3,5), (5,3);
3248+insert into graph(origid, destid) values (5,6), (6,5);
3249+
3250+select linkid from graph where latch = 2 and origid = 1 and weight = 1;
3251+
3252+select linkid from graph where latch = 2 and origid = 1 and weight = 2;
3253+
3254+select linkid from graph
3255+where latch = 2 and origid = 1 and (weight = 1 or weight = 2);

Subscribers

People subscribed via source and target branches

to status/vote changes: