1 /*
2    Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #ifndef HUGO_QUERY_BUILDER_HPP
26 #define HUGO_QUERY_BUILDER_HPP
27 
28 #include <NDBT.hpp>
29 #include <Vector.hpp>
30 #include "../../src/ndbapi/NdbQueryBuilder.hpp"
31 
32 class HugoQueryBuilder {
33 public:
34 
35   typedef Uint64 OptionMask;
36 
37   /**
38    * Options that affects what kind of query is built
39    */
40   enum QueryOption
41   {
42     /**
43      * Query should be a lookup
44      */
45     O_LOOKUP = 0x1,
46 
47     /**
48      * Query should be a scan
49      */
50     O_SCAN = 0x2,
51 
52     /**
53      * Query might use primary key index
54      */
55     O_PK_INDEX = 0x4,
56 
57     /**
58      * Query might use unique index
59      */
60     O_UNIQUE_INDEX = 0x8,
61 
62     /**
63      * Query might use ordered index
64      */
65     O_ORDERED_INDEX = 0x10,
66 
67     /**
68      * Query might table scan
69      */
70     O_TABLE_SCAN = 0x20,
71 
72     /**
73      * If not any options set, random query qill be created
74      */
75     O_RANDOM_OPTIONS = (OptionMask)((~(OptionMask)0) &
76                                     ~(OptionMask)(O_SCAN | O_LOOKUP))
77   };
78   static const OptionMask OM_RANDOM_OPTIONS = (OptionMask)O_RANDOM_OPTIONS;
79 
HugoQueryBuilder(Ndb * ndb,const NdbDictionary::Table ** tabptr,OptionMask om=OM_RANDOM_OPTIONS)80   HugoQueryBuilder(Ndb* ndb, const NdbDictionary::Table**tabptr,
81                    OptionMask om = OM_RANDOM_OPTIONS){
82     init();
83     for (; * tabptr != 0; tabptr++)
84       addTable(ndb, * tabptr);
85     setOptionMask(om);
86     fixOptions();
87   }
HugoQueryBuilder(Ndb * ndb,const NdbDictionary::Table * tab,QueryOption o)88   HugoQueryBuilder(Ndb* ndb, const NdbDictionary::Table* tab, QueryOption o) {
89     init();
90     addTable(ndb, tab);
91     setOption(o);
92     fixOptions();
93   }
94   virtual ~HugoQueryBuilder();
95 
setMinJoinLevel(int level)96   void setMinJoinLevel(int level) { m_joinLevel[0] = level;}
getMinJoinLevel() const97   int getMinJoinLevel() const { return m_joinLevel[0];}
setMaxJoinLevel(int level)98   void setMaxJoinLevel(int level) { m_joinLevel[1] = level;}
getMaxJoinLevel() const99   int getMaxJoinLevel() const { return m_joinLevel[1];}
100 
setJoinLevel(int level)101   void setJoinLevel(int level) { setMinJoinLevel(level);setMaxJoinLevel(level);}
102   int getJoinLevel() const;
103 
104   void addTable(Ndb*, const NdbDictionary::Table*);
105   void removeTable(const NdbDictionary::Table*);
106 
setOption(QueryOption o)107   void setOption(QueryOption o) { m_options |= (OptionMask)o;}
clearOption(QueryOption o) const108   void clearOption(QueryOption o) const { m_options &= ~(OptionMask)o;}
testOption(QueryOption o) const109   bool testOption(QueryOption o) const { return (m_options & o) != 0;}
110 
getOptionMask() const111   OptionMask getOptionMask() const { return m_options;}
setOptionMask(OptionMask om)112   void setOptionMask(OptionMask om) { m_options = om;}
113 
114   const NdbQueryDef * createQuery(bool takeOwnership = false);
115 
116 private:
117   struct TableDef
118   {
119     const NdbDictionary::Table * m_table;
120     Vector<const NdbDictionary::Index*> m_unique_indexes;
121     Vector<const NdbDictionary::Index*> m_ordered_indexes;
122   };
123 
124   void init();
125   mutable OptionMask m_options;
126   int m_joinLevel[2]; // min/max
127   Vector<TableDef> m_tables;
128   Vector<const NdbQueryDef*> m_queries;
129 
130   // get random table
131   struct TableDef getTable() const;
132 
133   struct OpIdx
134   {
135     NdbQueryOperationDef::Type m_type;
136     const NdbDictionary::Table * m_table;
137     const NdbDictionary::Index * m_index;
138   };
139   OpIdx getOp() const;
140 
141   struct Op
142   {
143     int m_parent;
144     int m_idx;
145     const NdbQueryOperationDef * m_op;
146   };
147 
148   Vector<Op> m_query; // Query built sofar
149 
150   /**
151    * Check if all column in cols can be bound to a column in tables in
152    *   ops
153    */
154   static bool checkBindable(Vector<const NdbDictionary::Column*> cols,
155                             Vector<Op> ops,
156                             bool allow_bind_nullable);
157 
158   Vector<Op> getParents(OpIdx); //
159   NdbQueryOperand * createLink(NdbQueryBuilder&, const NdbDictionary::Column*,
160                                Vector<Op> & parents,
161                                bool allow_bind_nullable);
162   const NdbQueryOperationDef* createOp(NdbQueryBuilder&);
163 
164   void fixOptions();
165 
166   /**
167    * We currently don't support busy-scan joins
168    */
169   bool checkBusyScan(Op) const;
170   bool isAncestor(const Op& parent, const Op& child) const;
171 
172   friend NdbOut& operator<<(NdbOut& out, const HugoQueryBuilder::Op& op);
173 };
174 
175 #endif
176