1 /*
2    Copyright (c) 2011, 2021, Oracle and/or its affiliates.
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 Street, Fifth Floor, Boston, MA 02110-1301, USA */
23 
24 #ifndef NdbQueryOperation_H
25 #define NdbQueryOperation_H
26 
27 #include <ndb_types.h>
28 
29 // this file is currently not located in include/ndbapi
30 // which means that we need to use <> to include instead of ""
31 // for files located in include/ndbapi
32 
33 // this file is currently not located in include/ndbapi
34 // skip includes...and require them to be included first
35 // BUH!
36 
37 /* There is no way to forward declare nested class NdbDictionary::Column,
38  * so this header file must be included.*/
39 // #include <NdbDictionary.hpp>
40 
41 // Needed to get NdbQueryOptions::ScanOrdering.
42 // #include "NdbQueryBuilder.hpp"
43 // #include <NdbIndexScanOperation.hpp>
44 
45 
46 class Ndb;
47 struct NdbError;
48 class NdbParamOperand;
49 class NdbQueryOperation;
50 class NdbQueryOperationDef;
51 class NdbRecAttr;
52 class NdbTransaction;
53 class NdbRecord;
54 class NdbInterpretedCode;
55 
56 /** Opaque implementation classes*/
57 class NdbQueryImpl;
58 class NdbQueryOperationImpl;
59 
60 
61 /**********************  OVERVIEW    ***********************
62  *
63  * a NdbQuery is created when a NdbQueryDefinition is added to a
64  * NdbTransaction for execution with NdbTransaction::creatQuery().
65  *
66  * A NdbQuery is associated with a collection of NdbQueryOperation which
67  * are instantiated (1::1) to reflect the NdbQueryOperationDef objects
68  * which the NdbQueryDef consists of. The same NdbQueryDef may be used to
69  * instantiate multiple NdbQuery obejects.
70  *
71  * When we have an instantiated NdbQuery, we should either bind result buffers
72  * for retrieving entire rows from each operation,
73  * (aka NdbRecord interface,::setResultRowRef(), ::setResultRowBuf())
74  * or set up retrieval operations for each attribute values, (::getValue()).
75  *
76  * Optionally we may also:
77  *  - Specify a scan ordering for the result set (parent only)
78  *  - Add multiple bounds to a range scan, (::setBound()) (parent only)
79  *  - Append a filter condition for each operation (aka mysqlds pushed condition)
80  *
81  * The NdbQuery is then executed together with other pending operations
82  * in the next NdbTransaction::execute().
83  * The resultset available from a NdbQuery is natively a 'left outer join'
84  * between the parent / child operations. If an application is not interested
85  * in the 'outer part' of the resultset, it is its own responsibility to
86  * filter these rows. Same is valid for any filter condition which has
87  * not been appended to the NdbQuery.
88  *
89  *
90  * We provide two different interfaces for iterating the result set:
91  *
92  * The 'local cursor' (NdbQueryOperation::firstResult(), ::nextResult())
93  *   Will navigate the resultset, and fetch results, from this specific operation.
94  *   It will only be possible to navigate within those rows which depends
95  *   on the current row(s) from any ancestor of the operation.
96  *   The local cursor will only retrieve the results, or a NULL row,
97  *   resulting from its own operation. -> All child operations of a
98  *   renavigated local cursor should be navigated to ::firstResult()
99  *   to ensure that they contain results related to the renavigated parent.
100  *
101  * The 'global cursor' (NdbQuery::nextResult())
102  *   Will present the result set as a scan on the root operation
103  *   with rows from its child operations appearing in an unpredictable
104  *   order. A new set of results, or NULL rows, from *all* operations
105  *   in the query tree are retrieved for each ::nextResult().
106  *   NULL rows resulting from the outer joins may appear anywhere
107  *   inside the resultset.
108  *
109  * As the global cursor is implemented on top of the local cursors, it is
110  * possible to mix the usage of global and local cursors.
111  *
112  ************************************************************************/
113 class NdbQuery
114 {
115 private:
116   // Only constructable through ::buildQuery()
117   friend class NdbQueryImpl;
118   explicit NdbQuery(NdbQueryImpl& impl);
119   ~NdbQuery();
120 
121 public:
122   /** Possible return values from nextResult().*/
123   enum NextResultOutcome{
124     NextResult_error = -1,
125     NextResult_gotRow = 0,
126     NextResult_scanComplete = 1,
127     NextResult_bufferEmpty = 2
128   };
129 
130   Uint32 getNoOfOperations() const;
131 
132   // Get a specific NdbQueryOperation by ident specified
133   // when the NdbQueryOperationDef was created.
134   NdbQueryOperation* getQueryOperation(const char* ident) const;
135   NdbQueryOperation* getQueryOperation(Uint32 index) const;
136 //NdbQueryOperation* getQueryOperation(const NdbQueryOperationDef* def) const;
137 
138   Uint32 getNoOfParameters() const;
139   const NdbParamOperand* getParameter(const char* name) const;
140   const NdbParamOperand* getParameter(Uint32 num) const;
141 
142   int setBound(const NdbRecord *keyRecord,
143                const struct NdbIndexScanOperation::IndexBound *bound);
144 
145   /**
146    * Get the next tuple(s) from the global cursor on the query.
147    *
148    * Result row / columns will be updated in the respective result handlers
149    * as previously specified on each NdbQueryOperation either by assigning a
150    * NdbRecord/rowBuffer or assigning NdbRecAttr to each column to be retrieved.
151    *
152    * @param fetchAllowed  If set to false, then fetching is disabled
153    * @param forceSend If true send will occur immediately (see @ref secAdapt)
154    *
155    * When fetchAllowed is set to false,
156    * the NDB API will not request new batches from the NDB Kernel when
157    * all received rows have been exhausted, but will instead return 2
158    * from nextResult(), indicating that new batches must be
159    * requested. You must then call nextResult with fetchAllowed = true
160    * in order to contact the NDB Kernel for more records, after taking over
161    * locks as appropriate.
162    *
163    * @note: All result returned from a NdbQuery are handled as scan results
164    *       in a cursor like interface.(Even single tuple 'lookup' operations!)
165    *  - After ::execute() the current position of the result set is 'before'
166    *    the first row. There is no valid data yet in the 'RecAttr'
167    *    or NdbRecord associated with the NdbQueryOperation!
168    *  - ::nextResult() is required to retrieve the first row. This may
169    *    also cause any error / status info assicioated with the result set
170    *    iself to be returned (Like 'NoData', posible type conversion errors,
171    *    or constraint violations associated with each specific row in the
172    *    result set.)
173    *
174    * @return
175    * -  NextResult_error (-1):       if unsuccessful,<br>
176    * -  NextResult_gotRow (0):       if another tuple was received, and<br>
177    * -  NextResult_scanComplete (1): if there are no more tuples to scan.
178    * -  NextResult_bufferEmpty (2):  if there are no more cached records
179    *                                 in NdbApi
180    */
181   NextResultOutcome nextResult(bool fetchAllowed = true,
182                                bool forceSend = false);
183 
184   /**
185    * Get NdbTransaction object for this query operation
186    */
187   NdbTransaction* getNdbTransaction() const;
188 
189   /**
190    * Close query.
191    *
192    * Will release most of the internally allocated objects owned
193    * by this NdbQuery and detach itself from the NdbQueryDef
194    * used to instantiate it.
195    *
196    * The application may destruct the NdbQueryDef after
197    * ::close() has been called on *all* NdbQuery objects
198    * instantiated from it.
199    */
200   void close(bool forceSend = false);
201 
202   /**
203    * @name Error Handling
204    * @{
205    */
206 
207   /**
208    * Get error object with information about the latest error.
209    *
210    * @return An error object with information about the latest error.
211    */
212   const NdbError& getNdbError() const;
213 
214   /** Get object implementing NdbQuery interface.*/
getImpl() const215   NdbQueryImpl& getImpl() const
216   { return m_impl; }
217 
218   /**
219    * Check if this is a pruned range scan. A range scan is pruned if the ranges
220    * are such that only a subset of the fragments need to be scanned for
221    * matching tuples.
222    *
223    * @param pruned This will be set to true if the operation is a pruned range
224    * scan.
225    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
226    */
227   int isPrunable(bool& pruned) const;
228 
229 private:
230   /** Opaque implementation NdbQuery interface.*/
231   NdbQueryImpl& m_impl;
232 
233 }; // class NdbQuery
234 
235 
236 
237 
238 class NdbQueryOperation
239 {
240 private:
241   // Only constructable through executing a NdbQueryDef
242   friend class NdbQueryOperationImpl;
243   explicit NdbQueryOperation(NdbQueryOperationImpl& impl);
244   ~NdbQueryOperation();
245 
246 public:
247   // Collection of get'ers to navigate in root, parent/child hierarchy
248 
249   Uint32 getNoOfParentOperations() const;
250   NdbQueryOperation* getParentOperation(Uint32 parentNo) const;
251 
252   Uint32 getNoOfChildOperations() const;
253   NdbQueryOperation* getChildOperation(Uint32 childNo) const;
254 
255   const NdbQueryOperationDef& getQueryOperationDef() const;
256 
257   // Get the entire query object which this operation is part of
258   NdbQuery& getQuery() const;
259 
260 
261 
262   /**
263    * Defines a retrieval operation of an attribute value.
264    * The NDB API allocate memory for the NdbRecAttr object that
265    * will hold the returned attribute value.
266    *
267    * @note Note that it is the applications responsibility
268    *       to allocate enough memory for resultBuffer (if non-NULL).
269    *       The buffer resultBuffer supplied by the application must be
270    *       aligned appropriately.  The buffer is used directly
271    *       (avoiding a copy penalty) only if it is aligned on a
272    *       4-byte boundary and the attribute size in bytes
273    *       (i.e. NdbRecAttr::attrSize times NdbRecAttr::arraySize is
274    *       a multiple of 4).
275    *
276    * @note There are three versions of NdbQueryOperation::getValue with
277    *       slightly different parameters.
278    *
279    * @note This method does not fetch the attribute value from
280    *       the database!  The NdbRecAttr object returned by this method
281    *       is <em>not</em> readable/printable before the
282    *       transaction has been executed with NdbTransaction::execute.
283    *
284    * @param anAttrName   Attribute name
285    * @param resultBuffer If this is non-NULL, then the attribute value
286    *                     will be returned in this parameter.<br>
287    *                     If NULL, then the attribute value will only
288    *                     be stored in the returned NdbRecAttr object.
289    * @return             An NdbRecAttr object to hold the value of
290    *                     the attribute, or a NULL pointer
291    *                     (indicating error).
292    */
293   NdbRecAttr* getValue(const char* anAttrName, char* resultBuffer = 0);
294   NdbRecAttr* getValue(Uint32 anAttrId, char* resultBuffer = 0);
295   NdbRecAttr* getValue(const NdbDictionary::Column* column,
296 		       char* resultBuffer = 0);
297 
298   /**
299    * Retrieval of entire or partial rows may also be specified. For partial
300    * retrieval a bitmask should supplied.
301    *
302    * The behaviour of mixing NdbRecord retrieval style with NdbRecAttr is
303    * is undefined - It should probably not be allowed.
304    *
305    * @param rec  Is a pointer to a NdbRecord specifying the byte layout of the
306    *             result row.
307    *
308    * @resBuffer  Defines a buffer sufficient large to hold the result row.
309    *
310    * @bufRef     Refers a pointer which will be updated to refer the current result row
311    *             for this operand.
312    *
313    * @param  result_mask defines as subset of attributes to read.
314    *         The column is only affected if 'mask[attrId >> 3]  & (1<<(attrId & 7))' is set
315    * @return 0 on success, -1 otherwise (call getNdbError() for details).
316    */
317   int setResultRowBuf (const NdbRecord *rec,
318                        char* resBuffer,
319                        const unsigned char* result_mask = 0);
320 
321   int setResultRowRef (const NdbRecord* rec,
322                        const char* & bufRef,
323                        const unsigned char* result_mask = 0);
324 
325   // TODO: define how BLOB/CLOB should be retrieved.
326   // ... Replicate ::getBlobHandle() from NdbOperation class?
327 
328   /** Get object implementing NdbQueryOperation interface.*/
getImpl() const329   NdbQueryOperationImpl& getImpl() const
330   { return m_impl; }
331 
332   /** Define result ordering for ordered index scan. It is an error to call
333    * this method on an operation that is not a scan, or to call it if an
334    * ordering was already set on the operation defintion by calling
335    * NdbQueryOperationDef::setOrdering().
336    * @param ordering The desired ordering of results.
337    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
338    */
339   int setOrdering(NdbQueryOptions::ScanOrdering ordering);
340 
341   /** Get the result ordering for this operation.*/
342   NdbQueryOptions::ScanOrdering getOrdering() const;
343 
344   /**
345    * Set the number of fragments to be scanned in parallel. This only applies
346    * to table scans and non-sorted scans of ordered indexes. This method is
347    * only implemented for then root scan operation.
348    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
349    */
350   int setParallelism(Uint32 parallelism);
351 
352   /**
353    * Set the number of fragments to be scanned in parallel to the maximum
354    * possible value. This is the default for the root scan operation.
355    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
356    */
357   int setMaxParallelism();
358 
359   /**
360    * Let the system dynamically choose the number of fragments to scan in
361    * parallel. The system will try to choose a value that gives optimal
362    * performance. This is the default for all scans but the root scan. This
363    * method only implemented for non-root scan operations.
364    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
365    */
366   int setAdaptiveParallelism();
367 
368   /** Set the batch size (max rows per batch) for this operation. This
369    * only applies to scan operations, as lookup operations always will
370    * have the same batch size as its parent operation, or 1 if it is the
371    * root operation.
372    * @param batchSize Batch size (in number of rows). A value of 0 means
373    * use the default batch size.
374    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
375    */
376   int setBatchSize(Uint32 batchSize);
377 
378   /**
379    * Set the NdbInterpretedCode needed for defining a conditional filter
380    * (aka: predicate) for this operation. Might be used both on scan
381    * and lookup operations.
382    *
383    * Typically, one would create NdbScanFilter and NdbInterpretedCode objects
384    * on the stack, e.g.:
385    *   NdbInterpretedCode code(table);
386    *   NdbScanFilter filter(code);
387    *   filter.begin();
388    *   filter.ge(0, 5U); // Check if column 1 is greater of equal to 5.
389    *   filter.end();
390    *   queryOp->setInterpretedCode(code);
391    *
392    * @param code The interpreted code. This object is copied internally,
393    * meaning that 'code' may be destroyed as soon as this method returns.
394    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
395    */
396   int setInterpretedCode(const NdbInterpretedCode& code) const;
397 
398   /**
399    * Local cursor:
400    *
401    * Navigate to first result row in this batch of results which
402    * depends on the current row(s) from all its ancestors.
403    * @return
404    * -  NextResult_error (-1):       if unsuccessful,<br>
405    * -  NextResult_gotRow (0):       if another tuple was received, and<br>
406    * -  NextResult_scanComplete (1): if there are no more tuples to scan.
407    * -  NextResult_bufferEmpty (2):  if there are no more cached records
408    *                                 in NdbApi
409    */
410   NdbQuery::NextResultOutcome firstResult();
411 
412   /**
413    * Local cursor:
414    *
415    * Get the next tuple(s) from this operation (and all its descendants?)
416    * which depends on the current row(s) from all its ancestors.
417    *
418    * Result row / columns will be updated in the respective result handlers
419    * as previously specified on each NdbQueryOperation either by assigning a
420    * NdbRecord/rowBuffer or assigning NdbRecAttr to each column to be retrieved.
421    *
422    * If the set of cached records in the NdbApi has been consumed, more will be
423    * requested from the datanodes only iff:
424    *    - This NdbOperation is the root of the entire pushed NdbQuery.
425    *    - 'fetchAllowed==true'
426    *
427    * The arguments fetchAllowed and forceSend are ignored if this operation is
428    * not the root of the pushed query.
429    *
430    * @return
431    * -  NextResult_error (-1):       if unsuccessful,<br>
432    * -  NextResult_gotRow (0):       if another tuple was received, and<br>
433    * -  NextResult_scanComplete (1): if there are no more tuples to scan.
434    * -  NextResult_bufferEmpty (2):  if there are no more cached records
435    *                                 in NdbApi
436    */
437   NdbQuery::NextResultOutcome nextResult(
438                                bool fetchAllowed = true,
439                                bool forceSend = false);
440 
441   // Result handling for this NdbQueryOperation
442   bool isRowNULL() const;    // Row associated with Operation is NULL value?
443 
444   bool isRowChanged() const; // Prev ::nextResult() on NdbQuery retrived a new
445                              // value for this NdbQueryOperation
446 
447 
448 private:
449   // Opaque implementation class instance.
450   NdbQueryOperationImpl& m_impl;
451 
452 }; // class NdbQueryOperation
453 
454 
455 class NdbQueryParamValue
456 {
457 public:
458 
459   // Raw data formated according to bound Column format.
460   // NOTE: This is how mysqld prepare parameter values!
461   NdbQueryParamValue(const void* val, bool shrinkVarChar= false);
462 
463   // C-type string, terminated by '\0'
464   NdbQueryParamValue(const char* val);
465 
466   // NULL-value, also used as optional end marker
467   NdbQueryParamValue();
468   NdbQueryParamValue(Uint16 val);
469   NdbQueryParamValue(Uint32 val);
470   NdbQueryParamValue(Uint64 val);
471   NdbQueryParamValue(double val);
472 
473   // More parameter C'tor to be added when required:
474 //NdbQueryParamValue(Uint8 val);
475 //NdbQueryParamValue(Int8 val);
476 //NdbQueryParamValue(Int16 val);
477 //NdbQueryParamValue(Int32 val);
478 //NdbQueryParamValue(Int64 val);
479 
480   /**
481    * Serialize value into a seuqence of words suitable to be sent to the data
482    * nodes.
483    * @param column Specifies the format that the value should be serialized
484    * into.
485    * @param dst Seralized data are appended to this.
486    * @param len Length of serialized data (in number of bytes).
487    * @param isNull Will be set to true iff this is a NULL value.
488    * @return 0 if ok, otherwise an error code.
489    */
490   int serializeValue(const class NdbColumnImpl& column,
491                      class Uint32Buffer& dst,
492                      Uint32& len,
493                      bool& isNull) const;
494 
495 private:
496   int m_type;
497 
498   union
499   {
500     Uint8     uint8;
501     Int8      int8;
502     Uint16    uint16;
503     Int16     int16;
504     Uint32    uint32;
505     Int32     int32;
506     Uint64    uint64;
507     Int64     int64;
508     double    dbl;
509     const char* string;
510     const void* raw;
511   } m_value;
512 };
513 
514 #endif
515