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 NdbQueryOperationImpl_H
25 #define NdbQueryOperationImpl_H
26 
27 #include "NdbQueryOperation.hpp"
28 #include "NdbQueryBuilderImpl.hpp"
29 #include "NdbIndexScanOperation.hpp"
30 #include <NdbError.hpp>
31 #include <ndb_limits.h>
32 #include <Vector.hpp>
33 
34 // Forward declarations
35 class NdbTableImpl;
36 class NdbIndexImpl;
37 class NdbApiSignal;
38 class NdbResultStream;
39 class NdbParamOperand;
40 class NdbTransaction;
41 class NdbReceiver;
42 class NdbOut;
43 class NdbRootFragment;
44 
45 /**
46  * This class simplifies the task of allocating memory for many instances
47  * of the same type at once and then constructing them later.
48  */
49 class NdbBulkAllocator
50 {
51 public:
52   /**
53    * @param[in] objSize Size (in bytes) of each object.
54    */
55   explicit NdbBulkAllocator(size_t objSize);
~NdbBulkAllocator()56   ~NdbBulkAllocator()
57   { reset(); };
58 
59   /**
60    * Allocate memory for a number of objects from the heap.
61    * @param[in] maxObjs The maximal number of objects this instance should
62    * accomodate.
63    * @return 0 or possible error code.
64    */
65   int init(Uint32 maxObjs);
66 
67   /** Release allocated memory to heap and reset *this to initial state.*/
68   void reset();
69 
70   /**
71    * Get an area large enough to hold 'noOfObjs' objects.
72    * @return The memory area.
73    */
74   void* allocObjMem(Uint32 noOfObjs);
75 private:
76   /** An end marker for checking for buffer overrun.*/
77   static const char endMarker = -15;
78 
79   /** Size of each object (in bytes).*/
80   const size_t m_objSize;
81 
82   /** The number of objects this instance can accomodate.*/
83   Uint32 m_maxObjs;
84 
85   /** The allocated memory area.*/
86   char* m_buffer;
87 
88   /** The number of object areas allocated so far.*/
89   Uint32 m_nextObjNo;
90 
91   // No copying.
92   NdbBulkAllocator(const NdbBulkAllocator&);
93   NdbBulkAllocator& operator= (const NdbBulkAllocator&);
94 };
95 
96 /** This class is the internal implementation of the interface defined by
97  * NdbQuery. This class should thus not be visible to the application
98  * programmer. @see NdbQuery.*/
99 class NdbQueryImpl {
100 
101   /* NdbQueryOperations are allowed to access it containing query */
102   friend class NdbQueryOperationImpl;
103 
104   /** For debugging.*/
105   friend NdbOut& operator<<(NdbOut& out, const class NdbQueryOperationImpl&);
106 
107 public:
108   /** Factory method which instantiate a query from its definition.
109    (There is no public constructor.)*/
110   static NdbQueryImpl* buildQuery(NdbTransaction& trans,
111                                   const NdbQueryDefImpl& queryDef);
112 
113   /** Return number of operations in query.*/
114   Uint32 getNoOfOperations() const;
115 
116   /**
117    * return number of leaf-operations
118    */
119   Uint32 getNoOfLeafOperations() const;
120 
121   // Get a specific NdbQueryOperation instance by ident specified
122   // when the NdbQueryOperationDef was created.
123   NdbQueryOperationImpl& getQueryOperation(Uint32 ident) const;
124   NdbQueryOperationImpl* getQueryOperation(const char* ident) const;
125   // Consider to introduce these as convenient shortcuts
126 //NdbQueryOperationDefImpl& getQueryOperationDef(Uint32 ident) const;
127 //NdbQueryOperationDefImpl* getQueryOperationDef(const char* ident) const;
128 
129   /** Return number of parameter operands in query.*/
130   Uint32 getNoOfParameters() const;
131   const NdbParamOperand* getParameter(const char* name) const;
132   const NdbParamOperand* getParameter(Uint32 num) const;
133 
134   /** Get the next tuple(s) from the global cursor on the query.
135    * @param fetchAllowed If true, the method may block while waiting for more
136    * results to arrive. Otherwise, the method will return immediately if no more
137    * results are buffered in the API.
138    * @param forceSend FIXME: Describe this.
139    * @return
140    * -  NextResult_error (-1):       if unsuccessful,<br>
141    * -  NextResult_gotRow (0):       if another tuple was received, and<br>
142    * -  NextResult_scanComplete (1): if there are no more tuples to scan.
143    * -  NextResult_bufferEmpty (2):  if there are no more cached records
144    *                                 in NdbApi
145    * @see NdbQueryOperation::nextResult()
146    */
147   NdbQuery::NextResultOutcome nextResult(bool fetchAllowed, bool forceSend);
148 
149   /** Close query:
150    *  - Release datanode resources,
151    *  - Discard pending result sets,
152    *  - Delete internal buffer and structures for receiving results.
153    *  - Disconnect with NdbQueryDef - it might now be destructed .
154    */
155   int close(bool forceSend);
156 
157   /** Deallocate 'this' NdbQuery object and its NdbQueryOperation objects.
158    *  If not already closed, it will also ::close() the NdbQuery.
159    */
160   void release();
161 
getNdbTransaction() const162   NdbTransaction& getNdbTransaction() const
163   { return m_transaction; }
164 
165   const NdbError& getNdbError() const;
166 
167   void setErrorCode(int aErrorCode);
168 
169   /** Assign supplied parameter values to the parameter placeholders
170    *  created when the query was defined.
171    *  Values are *copied* into this NdbQueryImpl object:
172    *  Memory location used as source for parameter values don't have
173    *  to be valid after this assignment.
174    */
175   int assignParameters(const NdbQueryParamValue paramValues[]);
176 
177   int setBound(const NdbRecord *keyRecord,
178                const NdbIndexScanOperation::IndexBound *bound);
179 
180   /** Prepare for execution.
181    *  @return possible error code.
182    */
183   int prepareSend();
184 
185   /** Send prepared signals from this NdbQuery to start execution
186    *  @return #signals sent, -1 if error.
187    */
188   int doSend(int aNodeId, bool lastFlag);
189 
getInterface()190   NdbQuery& getInterface()
191   { return m_interface; }
192 
193   /** Get next query in same transaction.*/
getNext() const194   NdbQueryImpl* getNext() const
195   { return m_next; }
196 
setNext(NdbQueryImpl * next)197   void setNext(NdbQueryImpl* next)
198   { m_next = next; }
199 
200   /** Get the (transaction independent) definition of this query. */
getQueryDef() const201   const NdbQueryDefImpl& getQueryDef() const
202   {
203     assert(m_queryDef);
204     return *m_queryDef;
205   }
206 
207   /** Process TCKEYCONF message. Return true if query is complete. */
208   bool execTCKEYCONF();
209 
210   /** Process SCAN_TABCONF w/ EndOfData which is a 'Close Scan Reply'. */
211   void execCLOSE_SCAN_REP(int errorCode, bool needClose);
212 
213   /** Determines if query has completed and may be garbage collected
214    *  A query is not considder complete until the client has
215    *  called the ::close() or ::release() method on it.
216    */
hasCompleted() const217   bool hasCompleted() const
218   { return (m_state == Closed);
219   }
220 
221   /**
222    * Mark this query as the first query or operation in a new transaction.
223    * This should only be called for queries where root operation is a lookup.
224    */
setStartIndicator()225   void setStartIndicator()
226   {
227     assert(!getQueryDef().isScanQuery());
228     m_startIndicator = true;
229   }
230 
231   /**
232    * Mark this query as the last query or operation in a transaction, after
233    * which the transaction should be committed. This should only be called
234    * for queries where root operation is a lookup.
235    */
setCommitIndicator()236   void setCommitIndicator()
237   {
238     assert(!getQueryDef().isScanQuery());
239     m_commitIndicator = true;
240   }
241 
242   /**
243    * Check if this is a pruned range scan. A range scan is pruned if the ranges
244    * are such that only a subset of the fragments need to be scanned for
245    * matching tuples.
246    *
247    * @param pruned This will be set to true if the operation is a pruned range
248    * scan.
249    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
250    */
251   int isPrunable(bool& pruned);
252 
253   /** Get the number of fragments to be read for the root operation.*/
getRootFragCount() const254   Uint32 getRootFragCount() const
255   { return m_rootFragCount; }
256 
getResultStreamAlloc()257   NdbBulkAllocator& getResultStreamAlloc()
258   { return m_resultStreamAlloc; }
259 
getTupleSetAlloc()260   NdbBulkAllocator& getTupleSetAlloc()
261   { return m_tupleSetAlloc; }
262 
getRowBufferAlloc()263   NdbBulkAllocator& getRowBufferAlloc()
264   { return m_rowBufferAlloc; }
265 
266 private:
267   /** Possible return values from NdbQueryImpl::awaitMoreResults.
268    * A subset of the integer values also matches those returned
269    * from PoolGuard::wait_scan().
270    */
271   enum FetchResult{
272     FetchResult_gotError = -4,  // There is an error avail in 'm_error.code'
273     FetchResult_sendFail = -3,
274     FetchResult_nodeFail = -2,
275     FetchResult_timeOut = -1,
276     FetchResult_ok = 0,
277     FetchResult_noMoreData = 1,
278     FetchResult_noMoreCache = 2
279   };
280 
281   /**
282    * Container of root fragments that the application is currently
283    * iterating over. 'Owned' by application thread and can be accesed
284    * without requiring a mutex lock.
285    * RootFragments are appended to a OrderedFragSet by ::prepareMoreResults()
286    *
287    */
288   class OrderedFragSet{
289   public:
290     // For calculating need for dynamically allocated memory.
291     static const Uint32 pointersPerFragment = 2;
292 
293     explicit OrderedFragSet();
294 
295     ~OrderedFragSet();
296 
297     /**
298      * Prepare internal datastructures.
299      * param[in] allocator For allocating arrays of pointers.
300      * param[in] ordering Possible scan ordering.
301      * param[in] capacity Max no of root fragments.
302      * @return 0 if ok, else errorcode
303      */
304     void prepare(NdbBulkAllocator& allocator,
305                  NdbQueryOptions::ScanOrdering ordering,
306                  int capacity,
307                  const NdbRecord* keyRecord,
308                  const NdbRecord* resultRecord);
309 
310     /**
311      * Add root fragments with completed ResultSets to this OrderedFragSet.
312      * The PollGuard mutex must locked, and under its protection
313      * completed root fragments are 'consumed' from rootFrags[] and
314      * added to OrderedFragSet where it become available for the
315      * application thread.
316      */
317     void prepareMoreResults(NdbRootFragment rootFrags[], Uint32 cnt);  // Need mutex lock
318 
319     /** Get the root fragment from which to read the next row.*/
320     NdbRootFragment* getCurrent() const;
321 
322     /**
323      * Re-organize the fragments after a row has been consumed. This is
324      * needed to remove fragments that has been emptied, and to re-sort
325      * fragments if doing a sorted scan.
326      */
327     void reorganize();
328 
329     /** Reset object to an empty state.*/
330     void clear();
331 
332     /**
333      * Get all fragments where more rows may be (pre-)fetched.
334      * (This method is not idempotent - the fragments are removed
335      * from the set.)
336      * @return Number of fragments (in &frags) from which more
337      * results should be requested.
338      */
339     Uint32 getFetchMore(NdbRootFragment** &rootFrags);
340 
341   private:
342 
343     /** No of fragments to read until '::finalBatchReceived()'.*/
344     int m_capacity;
345     /** Number of fragments in 'm_activeFrags'.*/
346     int m_activeFragCount;
347     /** Number of fragments in 'm_fetchMoreFrags'. */
348     int m_fetchMoreFragCount;
349 
350     /**
351      * Number of fragments where the final ResultSet has been received.
352      * (But not necessarily consumed!).
353      */
354     int m_finalFragReceivedCount;
355     /**
356      * Number of fragments where the final ResultSet has been received
357      * and consumed.
358      */
359     int m_finalFragConsumedCount;
360 
361     /** Ordering of index scan result.*/
362     NdbQueryOptions::ScanOrdering m_ordering;
363     /** Needed for comparing records when ordering results.*/
364     const NdbRecord* m_keyRecord;
365     /** Needed for comparing records when ordering results.*/
366     const NdbRecord* m_resultRecord;
367     /**
368      * Fragments where some tuples in the current ResultSet has not
369      * yet been consumed.
370      */
371     NdbRootFragment** m_activeFrags;
372     /**
373      * Fragments from which we should request more ResultSets.
374      * Either due to the current ResultSets has been consumed,
375      * or double buffering of ResultSets allows us to request
376      * another batch before the current has been consumed.
377      */
378     NdbRootFragment** m_fetchMoreFrags;
379 
380     /** Add a complete fragment that has been received.*/
381     void add(NdbRootFragment& frag);
382 
383     /** For sorting fragment reads according to index value of first record.
384      * Also f1<f2 if f2 has reached end of data and f1 has not.
385      * @return 1 if f1>f2, 0 if f1==f2, -1 if f1<f2.*/
386     int compare(const NdbRootFragment& frag1,
387                 const NdbRootFragment& frag2) const;
388 
389     /** For debugging purposes.*/
390     bool verifySortOrder() const;
391 
392     // No copying.
393     OrderedFragSet(const OrderedFragSet&);
394     OrderedFragSet& operator=(const OrderedFragSet&);
395   }; // class OrderedFragSet
396 
397   /** The interface that is visible to the application developer.*/
398   NdbQuery m_interface;
399 
400   enum {        // State of NdbQuery in API
401     Initial,    // Constructed object, assiciated with a defined query
402     Defined,    // Parameter values has been assigned
403     Prepared,   // KeyInfo & AttrInfo prepared for execution
404     Executing,  // Signal with exec. req. sent to TC
405     EndOfData,  // All results rows consumed
406     Closed,     // Query has been ::close()'ed
407     Failed,
408     Destructed
409   } m_state;
410 
411   enum {        // Assumed state of query cursor in TC block
412     Inactive,   // Execution not started at TC
413     Active
414   } m_tcState;
415 
416   /** Next query in same transaction.*/
417   NdbQueryImpl* m_next;
418   /** Definition of this query.*/
419   const NdbQueryDefImpl* m_queryDef;
420 
421   /** Possible error status of this query.*/
422   NdbError m_error;
423 
424   /**
425    * Possible error received from TC / datanodes.
426    * Only access w/ PollGuard mutex as it is set by receiver thread.
427    * Checked and moved into 'm_error' with ::hasReceivedError().
428    */
429   int m_errorReceived;   // BEWARE: protect with PollGuard mutex
430 
431   /** Transaction in which this query instance executes.*/
432   NdbTransaction& m_transaction;
433 
434   /** Scan queries creates their own sub transaction which they
435    *  execute within.
436    *  Has same transId, Ndb*, ++ as the 'real' transaction above.
437    */
438   NdbTransaction* m_scanTransaction;
439 
440   /** The operations constituting this query.*/
441   NdbQueryOperationImpl *m_operations;  // 'Array of ' OperationImpls
442   Uint32 m_countOperations;             // #elements in above array
443 
444   /** Current global cursor position. Refers the current NdbQueryOperation which
445    *  should be advanced to 'next' position for producing a new global set of results.
446    */
447   Uint32 m_globalCursor;
448 
449   /** Number of root fragments not yet completed within the current batch.
450    *  Only access w/ PollGuard mutex as it is also updated by receiver thread
451    */
452   Uint32 m_pendingFrags;  // BEWARE: protect with PollGuard mutex
453 
454   /** Number of fragments to be read by the root operation. (1 if root
455    * operation is a lookup)*/
456   Uint32 m_rootFragCount;
457 
458   /**
459    * This is an array with one element for each fragment that the root
460    * operation accesses (i.e. one for a lookup, all for a table scan).
461    * It keeps the state of the read operation on that fragment, and on
462    * any child operation instance derived from it.
463    */
464   NdbRootFragment* m_rootFrags;
465 
466   /** Root fragments that the application is currently iterating over. Only
467    * accessed by application thread.
468    */
469   OrderedFragSet m_applFrags;
470 
471   /** Number of root fragments for which confirmation for the final batch
472    * (with tcPtrI=RNIL) has been received. Observe that even if
473    * m_finalBatchFrags==m_rootFragCount, all tuples for the final batches may
474    * still not have been received (i.e. m_pendingFrags>0).
475    */
476   Uint32 m_finalBatchFrags; // BEWARE: protect with PollGuard mutex
477 
478   /** Number of IndexBounds set by API (index scans only) */
479   Uint32 m_num_bounds;
480 
481   /**
482    * Number of fields in the shortest bound (for an index scan root).
483    * Will be 0xffffffff if no bound has been set.
484    */
485   Uint32 m_shortestBound;
486 
487   /**
488    * Signal building section:
489    */
490   Uint32Buffer m_attrInfo;  // ATTRINFO: QueryTree + serialized parameters
491   Uint32Buffer m_keyInfo;   // KEYINFO:  Lookup key or scan bounds
492 
493   /** True if this query starts a new transaction. */
494   bool m_startIndicator;
495 
496   /** True if the transaction should be committed after executing this query.*/
497   bool m_commitIndicator;
498 
499   /** This field tells if the root operation is a prunable range scan. A range
500    * scan is pruned if the ranges are such that only a subset of the fragments
501    * need to be scanned for matching tuples. (Currently, pushed scans can only
502    * be pruned if is there is a single range that maps to a single fragment.
503    */
504   enum {
505     /** Call NdbQueryOperationDef::checkPrunable() to determine prunability.*/
506     Prune_Unknown,
507     Prune_Yes, // The root is a prunable range scan.
508     Prune_No   // The root is not a prunable range scan.
509   } m_prunability;
510 
511   /** If m_prunability==Prune_Yes, this is the hash value of the single
512    * fragment that should be scanned.*/
513   Uint32 m_pruneHashVal;
514 
515   /** Allocator for NdbQueryOperationImpl objects.*/
516   NdbBulkAllocator m_operationAlloc;
517 
518   /** Allocator for NdbResultStream::TupleSet objects.*/
519   NdbBulkAllocator m_tupleSetAlloc;
520 
521   /** Allocator for NdbResultStream objects.*/
522   NdbBulkAllocator m_resultStreamAlloc;
523 
524   /** Allocator for pointers.*/
525   NdbBulkAllocator m_pointerAlloc;
526 
527   /** Allocator for result row buffers.*/
528   NdbBulkAllocator m_rowBufferAlloc;
529 
530   // Only constructable from factory ::buildQuery();
531   explicit NdbQueryImpl(
532              NdbTransaction& trans,
533              const NdbQueryDefImpl& queryDef);
534 
535   ~NdbQueryImpl();
536 
537   /** Release resources after scan has returned last available result */
538   void postFetchRelease();
539 
540   /** Navigate to the next result from the root operation. */
541   NdbQuery::NextResultOutcome nextRootResult(bool fetchAllowed, bool forceSend);
542 
543   /** Send SCAN_NEXTREQ signal to fetch another batch from a scan query
544    * @return 0 if send succeeded, -1 otherwise.
545    */
546   int sendFetchMore(NdbRootFragment* rootFrags[], Uint32 cnt,
547                     bool forceSend);
548 
549   /** Wait for more scan results which already has been REQuested to arrive.
550    * @return 0 if some rows did arrive, a negative value if there are errors
551    * (in m_error.code),
552    * and 1 of there are no more rows to receive.
553    */
554   FetchResult awaitMoreResults(bool forceSend);
555 
556   /** Check if we have received an error from TC, or datanodes.
557    * @return 'true' if an error is pending, 'false' otherwise.
558    */
559   bool hasReceivedError();                                   // Need mutex lock
560 
561   void setFetchTerminated(int aErrorCode, bool needClose);   // Need mutex lock
562 
563   /** Close cursor on TC */
564   int closeTcCursor(bool forceSend);
565 
566   /** Send SCAN_NEXTREQ(close) signal to close cursor on TC and datanodes.
567    *  @return #signals sent, -1 if error.
568    */
569   int sendClose(int nodeId);
570 
getInterface() const571   const NdbQuery& getInterface() const
572   { return m_interface; }
573 
getRoot() const574   NdbQueryOperationImpl& getRoot() const
575   { return getQueryOperation(0U); }
576 
577   /** A complete batch has been received for a given root fragment
578    *  Update whatever required before the appl. is allowed to navigate
579    *  the result.
580    *  @return: 'true' if its time to resume appl. threads
581    */
582   bool handleBatchComplete(NdbRootFragment& rootFrag);
583 
getPointerAlloc()584   NdbBulkAllocator& getPointerAlloc()
585   { return m_pointerAlloc; }
586 
587 }; // class NdbQueryImpl
588 
589 
590 /** This class contains data members for NdbQueryOperation, such that these
591  *  do not need to exposed in NdbQueryOperation.hpp. This class may be
592  *  changed without forcing the customer to recompile his application.
593  */
594 class NdbQueryOperationImpl {
595 
596   /** For debugging.*/
597   friend NdbOut& operator<<(NdbOut& out, const NdbQueryOperationImpl&);
598 
599   friend class NdbQueryImpl;
600 
601 public:
602   Uint32 getNoOfParentOperations() const;
603   NdbQueryOperationImpl& getParentOperation(Uint32 i) const;
604   NdbQueryOperationImpl* getParentOperation() const;
605 
606   Uint32 getNoOfChildOperations() const;
607   NdbQueryOperationImpl& getChildOperation(Uint32 i) const;
608 
609   /** A shorthand for getting the root operation. */
getRoot() const610   NdbQueryOperationImpl& getRoot() const
611   { return m_queryImpl.getRoot(); }
612 
613   // A shorthand method.
getInternalOpNo() const614   Uint32 getInternalOpNo() const
615   {
616     return m_operationDef.getInternalOpNo();
617   }
618 
getQueryDef() const619   const NdbQueryDefImpl& getQueryDef() const
620   { return m_queryImpl.getQueryDef(); }
621 
getQueryOperationDef() const622   const NdbQueryOperationDefImpl& getQueryOperationDef() const
623   { return m_operationDef; }
624 
625   // Get the entire query object which this operation is part of
getQuery() const626   NdbQueryImpl& getQuery() const
627   { return m_queryImpl; }
628 
629   NdbRecAttr* getValue(const char* anAttrName, char* resultBuffer);
630   NdbRecAttr* getValue(Uint32 anAttrId, char* resultBuffer);
631   NdbRecAttr* getValue(const NdbColumnImpl&, char* resultBuffer);
632 
633   int setResultRowBuf (const NdbRecord *rec,
634                        char* resBuffer,
635                        const unsigned char* result_mask);
636 
637   int setResultRowRef (const NdbRecord* rec,
638                        const char* & bufRef,
639                        const unsigned char* result_mask);
640 
641   NdbQuery::NextResultOutcome firstResult();
642 
643   NdbQuery::NextResultOutcome nextResult(bool fetchAllowed, bool forceSend);
644 
645   bool isRowNULL() const;    // Row associated with Operation is NULL value?
646 
647   bool isRowChanged() const; // Prev ::nextResult() on NdbQuery retrieved a new
648                              // value for this NdbQueryOperation
649 
650   /** Process result data for this operation. Return true if batch complete.*/
651   bool execTRANSID_AI(const Uint32* ptr, Uint32 len);
652 
653   /** Process absence of result data for this operation. (Only used when the
654    * root operation is a lookup.)
655    * @return true if query complete.*/
656   bool execTCKEYREF(const NdbApiSignal* aSignal);
657 
658   /** Called once per complete (within batch) fragment when a SCAN_TABCONF
659    * signal is received.
660    * @param tcPtrI not in use.
661    * @param rowCount Number of rows for this fragment, including all rows from
662    * descendant lookup operations.
663    * @param receiver The receiver object that shall process the results.*/
664   bool execSCAN_TABCONF(Uint32 tcPtrI, Uint32 rowCount, Uint32 nodeMask,
665                         NdbReceiver* receiver);
666 
getInterface() const667   const NdbQueryOperation& getInterface() const
668   { return m_interface; }
getInterface()669   NdbQueryOperation& getInterface()
670   { return m_interface; }
671 
672   /** Define result ordering for ordered index scan. It is an error to call
673    * this method on an operation that is not a scan, or to call it if an
674    * ordering was already set on the operation defintion by calling
675    * NdbQueryOperationDef::setOrdering().
676    * @param ordering The desired ordering of results.
677    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
678    */
679   int setOrdering(NdbQueryOptions::ScanOrdering ordering);
680 
getOrdering() const681   NdbQueryOptions::ScanOrdering getOrdering() const
682   { return m_ordering; }
683 
684   /**
685    * Set the number of fragments to be scanned in parallel. This only applies
686    * to table scans and non-sorted scans of ordered indexes. This method is
687    * only implemented for then root scan operation.
688    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
689    */
690   int setParallelism(Uint32 parallelism);
691 
692   /**
693    * Set the number of fragments to be scanned in parallel to the maximum
694    * possible value. This is the default for the root scan operation.
695    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
696    */
697   int setMaxParallelism();
698 
699   /**
700    * Let the system dynamically choose the number of fragments to scan in
701    * parallel. The system will try to choose a value that gives optimal
702    * performance. This is the default for all scans but the root scan. This
703    * method only implemented for non-root scan operations.
704    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
705    */
706   int setAdaptiveParallelism();
707 
708   /** Set the batch size (max rows per batch) for this operation. This
709    * only applies to scan operations, as lookup operations always will
710    * have the same batch size as its parent operation, or 1 if it is the
711    * root operation.
712    * @param batchSize Batch size (in number of rows). A value of 0 means
713    * use the default batch size.
714    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
715    */
716   int setBatchSize(Uint32 batchSize);
717 
718   /**
719    * Set the NdbInterpretedCode needed for defining a scan filter for
720    * this operation.
721    * It is an error to call this method on a lookup operation.
722    * @param code The interpreted code. This object is copied internally,
723    * meaning that 'code' may be destroyed as soon as this method returns.
724    * @return 0 if ok, -1 in case of error (call getNdbError() for details.)
725    */
726   int setInterpretedCode(const NdbInterpretedCode& code);
727   bool hasInterpretedCode() const;
728 
729   /** Verify magic number.*/
checkMagicNumber() const730   bool checkMagicNumber() const
731   { return m_magic == MAGIC; }
732 
733   /** Get the maximal number of rows that may be returned in a single
734    *  SCANREQ to the SPJ block.
735    */
getMaxBatchRows() const736   Uint32 getMaxBatchRows() const
737   { return m_maxBatchRows; }
738 
739   /** Get size of buffer required to hold a full batch of 'packed' rows */
740   Uint32 getBatchBufferSize() const;
741 
742   /** Get size of a full row. */
743   Uint32 getRowSize() const;
744 
getNdbRecord() const745   const NdbRecord* getNdbRecord() const
746   { return m_ndbRecord; }
747 
748 private:
749 
750   STATIC_CONST (MAGIC = 0xfade1234);
751 
752   /** Interface for the application developer.*/
753   NdbQueryOperation m_interface;
754   /** For verifying pointers to this class.*/
755   const Uint32 m_magic;
756   /** NdbQuery to which this operation belongs. */
757   NdbQueryImpl& m_queryImpl;
758   /** The (transaction independent ) definition from which this instance
759    * was created.*/
760   const NdbQueryOperationDefImpl& m_operationDef;
761 
762   /* MAYBE: replace m_children with navigation via m_operationDef.getChildOperation().*/
763   /** Parent of this operation.*/
764   NdbQueryOperationImpl* m_parent;
765   /** Children of this operation.*/
766   Vector<NdbQueryOperationImpl*> m_children;
767 
768   /** Max rows (per resultStream) in a scan batch.*/
769   Uint32 m_maxBatchRows;
770 
771   /** Buffer for parameters in serialized format */
772   Uint32Buffer m_params;
773 
774   /** User specified buffer for final storage of result.*/
775   char* m_resultBuffer;
776   /** User specified pointer to application pointer that should be
777    * set to point to the current row inside a receiver buffer
778    * @see NdbQueryOperationImpl::setResultRowRef */
779   const char** m_resultRef;
780   /** True if this operation gave no result for the current row.*/
781   bool m_isRowNull;
782 
783   /** Result record & optional bitmask to disable read of selected cols.*/
784   const NdbRecord* m_ndbRecord;
785   const unsigned char* m_read_mask;
786 
787   /** Head & tail of NdbRecAttr list defined by this operation.
788     * Used for old-style result retrieval (using getValue()).*/
789   NdbRecAttr* m_firstRecAttr;
790   NdbRecAttr* m_lastRecAttr;
791 
792   /** Ordering of scan results (only applies to ordered index scans.)*/
793   NdbQueryOptions::ScanOrdering m_ordering;
794 
795   /** A scan filter is mapped to an interpeter code program, which is stored
796    * here. (This field is NULL if no scan filter has been defined.)*/
797   NdbInterpretedCode* m_interpretedCode;
798 
799   /** True if this operation reads from any disk column. */
800   bool m_diskInUserProjection;
801 
802   /** Number of scan fragments to read in parallel.
803    */
804   Uint32 m_parallelism;
805 
806   /** Size of each unpacked result row (in bytes).*/
807   mutable Uint32 m_rowSize;
808 
809   /** Size of the buffer required to hold a batch of result rows */
810   mutable Uint32 m_batchBufferSize;
811 
812   explicit NdbQueryOperationImpl(NdbQueryImpl& queryImpl,
813                                  const NdbQueryOperationDefImpl& def);
814   ~NdbQueryOperationImpl();
815 
816   /** Copy NdbRecAttr and/or NdbRecord results from stream into appl. buffers */
817   void fetchRow(NdbResultStream& resultStream);
818 
819   /** Set result for this operation and all its descendand child
820    *  operations to NULL.
821    */
822   void nullifyResult();
823 
824   /** Release resources after scan has returned last available result */
825   void postFetchRelease();
826 
827   /** Count number of descendant operations (excluding the operation itself) */
828   Int32 getNoOfDescendantOperations() const;
829 
830   /**
831    * Count number of leaf operations below/including self
832    */
833   Uint32 getNoOfLeafOperations() const;
834 
835   /** Serialize parameter values.
836    *  @return possible error code.*/
837   int serializeParams(const NdbQueryParamValue* paramValues);
838 
839   int serializeProject(Uint32Buffer& attrInfo);
840 
841   Uint32 calculateBatchedRows(const NdbQueryOperationImpl* closestScan);
842   void setBatchedRows(Uint32 batchedRows);
843 
844   /** Prepare ATTRINFO for execution. (Add execution params++)
845    *  @return possible error code.*/
846   int prepareAttrInfo(Uint32Buffer& attrInfo);
847 
848   /**
849    * Expand keys and bounds for the root operation into the KEYINFO section.
850    * @param keyInfo Actuall KEYINFO section the key / bounds are
851    *                put into
852    * @param actualParam Instance values for NdbParamOperands.
853    * Returns: 0 if OK, or possible an errorcode.
854    */
855   int prepareKeyInfo(Uint32Buffer& keyInfo,
856                      const NdbQueryParamValue* actualParam);
857 
858   int prepareLookupKeyInfo(
859                      Uint32Buffer& keyInfo,
860                      const NdbQueryOperandImpl* const keys[],
861                      const NdbQueryParamValue* actualParam);
862 
863   int prepareIndexKeyInfo(
864                      Uint32Buffer& keyInfo,
865                      const NdbQueryOperationDefImpl::IndexBound* bounds,
866                      const NdbQueryParamValue* actualParam);
867 
868   /** Return I-value (for putting in object map) for a receiver pointing back
869    * to this object. TCKEYCONF is processed by first looking up an
870    * NdbReceiver instance in the object map, and then following
871    * NdbReceiver::m_query_operation_impl here.*/
872   Uint32 getIdOfReceiver() const;
873 
874   /**
875    * If the operation has a scan filter, append the corresponding
876    * interpreter code to a buffer.
877    * @param attrInfo The buffer to which the code should be appended.
878    * @return possible error code */
879   int prepareInterpretedCode(Uint32Buffer& attrInfo) const;
880 
881   /** Returns true if this operation reads from any disk column. */
diskInUserProjection() const882   bool diskInUserProjection() const
883   { return m_diskInUserProjection; }
884 
885 }; // class NdbQueryOperationImpl
886 
887 
888 #endif
889