1 /*
2    Copyright (c) 2011, 2017, 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      * Column referrences may also include grandparents (Default 'on')
74      */
75     O_GRANDPARENT = 0x100
76   };
77   static const OptionMask OM_RANDOM_OPTIONS =
78        (OptionMask)(O_PK_INDEX | O_UNIQUE_INDEX | O_ORDERED_INDEX | O_TABLE_SCAN | O_GRANDPARENT);
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   : m_ndb(ndb)
83   {
84     init();
85     for (; * tabptr != 0; tabptr++)
86       addTable(*tabptr);
87     setOptionMask(om);
88     fixOptions();
89   }
HugoQueryBuilder(Ndb * ndb,const NdbDictionary::Table * tab,QueryOption o)90   HugoQueryBuilder(Ndb* ndb, const NdbDictionary::Table* tab, QueryOption o)
91   : m_ndb(ndb)
92   {
93     init();
94     addTable(tab);
95     setOption(o);
96     fixOptions();
97   }
98   virtual ~HugoQueryBuilder();
99 
setMinJoinLevel(int level)100   void setMinJoinLevel(int level) { m_joinLevel[0] = level;}
getMinJoinLevel() const101   int getMinJoinLevel() const { return m_joinLevel[0];}
setMaxJoinLevel(int level)102   void setMaxJoinLevel(int level) { m_joinLevel[1] = level;}
getMaxJoinLevel() const103   int getMaxJoinLevel() const { return m_joinLevel[1];}
104 
setJoinLevel(int level)105   void setJoinLevel(int level) { setMinJoinLevel(level);setMaxJoinLevel(level);}
106   int getJoinLevel() const;
107 
108   void addTable(const NdbDictionary::Table*);
109   void removeTable(const NdbDictionary::Table*);
110 
setOption(QueryOption o)111   void setOption(QueryOption o) { m_options |= (OptionMask)o;}
clearOption(QueryOption o) const112   void clearOption(QueryOption o) const { m_options &= ~(OptionMask)o;}
testOption(QueryOption o) const113   bool testOption(QueryOption o) const { return (m_options & o) != 0;}
114 
getOptionMask() const115   OptionMask getOptionMask() const { return m_options;}
setOptionMask(OptionMask om)116   void setOptionMask(OptionMask om) { m_options = om;}
117 
118   const NdbQueryDef * createQuery(bool takeOwnership = false);
119 
120 private:
121   const Ndb* m_ndb;
122 
123   struct TableDef
124   {
125     const NdbDictionary::Table * m_table;
126     Vector<const NdbDictionary::Index*> m_unique_indexes;
127     Vector<const NdbDictionary::Index*> m_ordered_indexes;
128   };
129 
130   void init();
131   mutable OptionMask m_options;
132   int m_joinLevel[2]; // min/max
133   Vector<TableDef> m_tables;
134   Vector<const NdbQueryDef*> m_queries;
135 
136   // get random table
137   struct TableDef getTable() const;
138 
139   struct OpIdx
140   {
141     NdbQueryOperationDef::Type m_type;
142     const NdbDictionary::Table * m_table;
143     const NdbDictionary::Index * m_index;
144   };
145   OpIdx getOp() const;
146 
147   struct Op
148   {
149     int m_parent;
150     int m_idx;
151     const NdbQueryOperationDef * m_op;
152   };
153 
154   Vector<Op> m_query; // Query built sofar
155 
156   /**
157    * Check if all column in cols can be bound to a column in tables in
158    *   ops
159    */
160   static bool checkBindable(Vector<const NdbDictionary::Column*> cols,
161                             Vector<Op> ops,
162                             bool allow_bind_nullable);
163 
164   Vector<Op> getParents(OpIdx); //
165   NdbQueryOperand * createLink(NdbQueryBuilder&, const NdbDictionary::Column*,
166                                Vector<Op> & parents,
167                                bool allow_bind_nullable);
168   const NdbQueryOperationDef* createOp(NdbQueryBuilder&);
169 
170   void fixOptions();
171 
172   /**
173    * We currently don't support busy-scan joins
174    */
175   bool checkBusyScan(Op) const;
176   bool isAncestor(const Op& parent, const Op& child) const;
177 
178   friend NdbOut& operator<<(NdbOut& out, const HugoQueryBuilder::Op& op);
179 };
180 
181 #endif
182