1 /*
2    Copyright (c) 2004, 2021, Oracle and/or its affiliates.
3     All rights reserved. Use is subject to license terms.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License, version 2.0,
7    as published by the Free Software Foundation.
8 
9    This program is also distributed with certain software (including
10    but not limited to OpenSSL) that is licensed under separate terms,
11    as designated in a particular file or component or in included license
12    documentation.  The authors of MySQL hereby grant you an additional
13    permission to link the program and your derivative works with the
14    separately licensed software that they have included with MySQL.
15 
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License, version 2.0, for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
24 */
25 
26 #ifndef NdbIndexScanOperation_H
27 #define NdbIndexScanOperation_H
28 
29 #include "NdbScanOperation.hpp"
30 
31 /**
32  * @class NdbIndexScanOperation
33  * @brief Class of scan operations for use to scan ordered index
34  */
35 class NdbIndexScanOperation : public NdbScanOperation {
36 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
37   friend class Ndb;
38   friend class NdbTransaction;
39   friend class NdbResultSet;
40   friend class NdbOperation;
41   friend class NdbScanOperation;
42   friend class NdbIndexStat;
43 #endif
44 
45 public:
46   /**
47    * readTuples using ordered index
48    * This method is used to specify details for an old Api Index Scan
49    * operation.
50    *
51    * @param lock_mode Lock mode
52    * @param scan_flags see @ref ScanFlag
53    * @param parallel No of fragments to scan in parallel (0=max)
54    */
55   virtual int readTuples(LockMode lock_mode = LM_Read,
56                          Uint32 scan_flags = 0,
57 			 Uint32 parallel = 0,
58 			 Uint32 batch = 0);
59 
60 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
61   /**
62    * readTuples using ordered index
63    *
64    * @param lock_mode Lock mode
65    * @param batch     No of rows to fetch from each fragment at a time
66    * @param parallel  No of fragments to scan in parallel
67    * @param order_by  Order result set in index order
68    * @param order_desc Order descending, ignored unless order_by
69    * @param read_range_no Enable reading of range no using @ref get_range_no
70    * @returns 0 for success and -1 for failure
71    * @see NdbScanOperation::readTuples
72    */
readTuples(LockMode lock_mode,Uint32 batch,Uint32 parallel,bool order_by,bool order_desc=false,bool read_range_no=false,bool keyinfo=false,bool multi_range=false)73   inline int readTuples(LockMode lock_mode,
74                         Uint32 batch,
75                         Uint32 parallel,
76                         bool order_by,
77                         bool order_desc = false,
78                         bool read_range_no = false,
79 			bool keyinfo = false,
80 			bool multi_range = false) {
81     Uint32 scan_flags =
82       (SF_OrderBy & -(Int32)order_by) |
83       (SF_Descending & -(Int32)order_desc) |
84       (SF_ReadRangeNo & -(Int32)read_range_no) |
85       (SF_KeyInfo & -(Int32)keyinfo) |
86       (SF_MultiRange & -(Int32)multi_range);
87 
88     return readTuples(lock_mode, scan_flags, parallel, batch);
89   }
90 #endif
91 
92   /**
93    * Type of ordered index key bound.  The values (0-4) will not change
94    * and can be used explicitly (e.g. they could be computed).
95    */
96   enum BoundType {
97     BoundLE = 0,        ///< lower bound
98     BoundLT = 1,        ///< lower bound, strict
99     BoundGE = 2,        ///< upper bound
100     BoundGT = 3,        ///< upper bound, strict
101     BoundEQ = 4         ///< equality
102   };
103 
104   /* Maximum number of ranges that can be supplied to a single
105    * NdbIndexScanOperation
106    */
107   enum {
108     MaxRangeNo= 0xfff
109   };
110 
111   /**
112    * Define bound on index key in range scan - old Api.
113    *
114    * Each index key can have lower and/or upper bound.  Setting the key
115    * equal to a value defines both upper and lower bounds.  The bounds
116    * can be defined in any order.  Conflicting definitions is an error.
117    *
118    * For equality, it is better to use BoundEQ instead of the equivalent
119    * pair of BoundLE and BoundGE.  This is especially true when table
120    * partition key is an initial part of the index key.
121    *
122    * The sets of lower and upper bounds must be on initial sequences of
123    * index keys.  All but possibly the last bound must be non-strict.
124    * So "a >= 2 and b > 3" is ok but "a > 2 and b >= 3" is not.
125    *
126    * The scan may currently return tuples for which the bounds are not
127    * satisfied.  For example, "a <= 2 and b <= 3" scans the index up to
128    * (a=2, b=3) but also returns any (a=1, b=4).
129    *
130    * NULL is treated like a normal value which is less than any not-NULL
131    * value and equal to another NULL value.  To compare against NULL use
132    * setBound with null pointer (0).
133    *
134    * An index stores also all-NULL keys.  Doing index scan with empty
135    * bound set returns all table tuples.
136    *
137    * @param attr        Attribute name, alternatively:
138    * @param type        Type of bound
139    * @param value       Pointer to bound value, 0 for NULL
140    * @return            0 if successful otherwise -1
141    *
142    * @note See comment under equal() about data format and length.
143    * @note See the two parameter setBound variant for use with NdbRecord
144    */
145 #ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
146   int setBound(const char* attr, int type, const void* value, Uint32 len);
147 #endif
148   int setBound(const char* attr, int type, const void* value);
149 
150   /**
151    * Define bound on index key in range scan using index column id.
152    * See the other setBound() method for details.
153    */
154 #ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
155   int setBound(Uint32 anAttrId, int type, const void* aValue, Uint32 len);
156 #endif
157   int setBound(Uint32 anAttrId, int type, const void* aValue);
158 
159   /**
160    * This method is called to separate sets of bounds (ranges) when
161    * defining an Index Scan with multiple ranges
162    * It can only be used with scans defined using the SF_MultiRange
163    * scan flag.
164    * For NdbRecord, ranges are specified using the IndexBound structure
165    * and the setBound() API.
166    * If an index scan has more than one range then end_of_bound must be
167    * called after every range, including the last.
168    * If the SF_ReadRangeNo flag is set then the range_no supplied when
169    * the range is defined will be associated with each row returned from
170    * that range.  This can be obtained by calling get_range_no().
171    * If SF_ReadRangeNo and SF_OrderBy flags are provided then range_no
172    * values must be strictly increasing (i.e. starting at zero and
173    * getting larger by 1 for each range specified).  This is to ensure
174    * that rows are returned in order.
175    */
176   int end_of_bound(Uint32 range_no= 0);
177 
178   /**
179    * Return range number for current row, as defined in the IndexBound
180    * structure used when the scan was defined.
181    * Only available if the SF_ReadRangeNo and SF_MultiRange flags were
182    * set in the ScanOptions::scan_flags structure passed to scanIndex().
183    */
184   int get_range_no();
185 
186   /* Structure used to describe index scan bounds, for NdbRecord scans. */
187   struct IndexBound {
188     /* Row containing lower bound, or NULL for scan from the start. */
189     const char *low_key;
190     /* Number of columns in lower bound, for bounding by partial prefix. */
191     Uint32 low_key_count;
192     /* True for less-than-or-equal, false for strictly less-than. */
193     bool low_inclusive;
194     /* Row containing upper bound, or NULL for scan to the end. */
195     const char * high_key;
196     /* Number of columns in upper bound, for bounding by partial prefix. */
197     Uint32 high_key_count;
198     /* True for greater-than-or-equal, false for strictly greater-than. */
199     bool high_inclusive;
200     /*
201       Value to identify this bound, may be read with get_range_no().
202       Must be <= MaxRangeNo (set to zero if not using range_no).
203       Note that for ordered scans, the range_no must be strictly increasing
204       for each range, or the result set will not be sorted correctly.
205     */
206     Uint32 range_no;
207   };
208 
209   /**
210    * Add a range to an NdbRecord defined Index scan
211    *
212    * This method is called to add a range to an IndexScan operation
213    * which has been defined with a call to NdbTransaction::scanIndex().
214    * To add more than one range, the index scan operation must have been
215    * defined with the the SF_MultiRange flag set.
216    *
217    * Where multiple numbered ranges are defined with multiple calls to
218    * setBound, and the scan is ordered, the range number for each range
219    * must be larger than the range number for the previously defined range.
220    *
221    * When the application knows that rows in-range will only be found in
222    * a particular partition, a PartitionSpecification can be supplied.
223    * This may be used to limit the scan to a single partition, improving
224    * system efficiency
225    * The sizeOfPartInfo parameter should be set to the
226    * sizeof(PartitionSpec) to enable backwards compatibility.
227    *
228    * @param key_record NdbRecord structure for the key the index is
229    *        defined on
230    * @param bound The bound to add
231    * @param partInfo Extra information to enable a reduced set of
232    *        partitions to be scanned.
233    * @param sizeOfPartInfo
234    *
235    * @return 0 for Success, other for Failure.
236    */
237   int setBound(const NdbRecord *key_record,
238                const IndexBound& bound);
239   int setBound(const NdbRecord *key_record,
240                const IndexBound& bound,
241                const Ndb::PartitionSpec* partInfo,
242                Uint32 sizeOfPartInfo= 0);
243 
244   /**
245    * Return size of data, in 32-bit words, that will be send to data nodes for
246    * all bounds added so far with setBound().
247    *
248    * This method is only available for NdbRecord index scans.
249    */
250   int getCurrentKeySize();
251 
252   /**
253    * Is current scan sorted?
254    */
getSorted() const255   bool getSorted() const { return m_ordered; }
256 
257   /**
258    * Is current scan sorted descending?
259    */
getDescending() const260   bool getDescending() const { return m_descending; }
261 
262 private:
263   NdbIndexScanOperation(Ndb* aNdb);
264   virtual ~NdbIndexScanOperation();
265 
266   int processIndexScanDefs(LockMode lm,
267                            Uint32 scan_flags,
268                            Uint32 parallel,
269                            Uint32 batch);
270   int scanIndexImpl(const NdbRecord *key_record,
271                     const NdbRecord *result_record,
272                     NdbOperation::LockMode lock_mode,
273                     const unsigned char *result_mask,
274                     const NdbIndexScanOperation::IndexBound *bound,
275                     const NdbScanOperation::ScanOptions *options,
276                     Uint32 sizeOfOptions);
277 
278   /* Structure used to collect information about an IndexBound
279    * as it is provided by the old Api setBound() calls
280    */
281 public:
282   struct OldApiBoundInfo
283   {
284     Uint32 highestKey;
285     bool highestSoFarIsStrict;
286     Uint32 keysPresentBitmap;
287     char* key;
288   };
289 
290 private:
291   struct OldApiScanRangeDefinition
292   {
293     /* OldApiBoundInfo used during definition
294      * IndexBound used once bound defined
295      * Todo : For heavy old Api use, consider splitting
296      * to allow NdbRecAttr use without malloc
297      */
298     union {
299       struct {
300         OldApiBoundInfo lowBound;
301         OldApiBoundInfo highBound;
302       } oldBound;
303 
304       IndexBound ib;
305     };
306     /* Space for key bounds
307      *   Low bound from offset 0
308      *   High bound from offset key_record->m_row_size
309      */
310     char space[1];
311   };
312 
313   int setBoundHelperOldApi(OldApiBoundInfo& boundInfo,
314                            Uint32 maxKeyRecordBytes,
315                            Uint32 index_attrId,
316                            Uint32 valueLen,
317                            bool inclusive,
318                            Uint32 byteOffset,
319                            Uint32 nullbit_byte_offset,
320                            Uint32 nullbit_bit_in_byte,
321                            const void *aValue);
322 
323   int setBound(const NdbColumnImpl*, int type, const void* aValue);
324   int buildIndexBoundOldApi(int range_no);
325   const IndexBound* getIndexBoundFromRecAttr(NdbRecAttr* recAttr);
326   void releaseIndexBoundsOldApi();
327   int ndbrecord_insert_bound(const NdbRecord *key_record,
328                              Uint32 column_index,
329                              const char *row,
330                              Uint32 bound_type,
331                              Uint32*& firstWordOfBound);
332   int insert_open_bound(const NdbRecord* key_record,
333                         Uint32*& firstWordOfBound);
334 
335   virtual int equal_impl(const NdbColumnImpl*, const char*);
336   virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char*);
337 
338   int getDistKeyFromRange(const NdbRecord* key_record,
339                           const NdbRecord* result_record,
340                           const char* row,
341                           Uint32* distKey);
342   void fix_get_values();
343   int next_result_ordered(bool fetchAllowed, bool forceSend = false);
344   int next_result_ordered_ndbrecord(const char * & out_row,
345                                     bool fetchAllowed,
346                                     bool forceSend);
347   void ordered_insert_receiver(Uint32 start, NdbReceiver *receiver);
348   int ordered_send_scan_wait_for_all(bool forceSend);
349   int send_next_scan_ordered(Uint32 idx);
350   int compare(Uint32 key, Uint32 cols, const NdbReceiver*, const NdbReceiver*);
351   Uint32 m_sort_columns;
352 
353   /* Number of IndexBounds for this scan (NdbRecord only) */
354   Uint32 m_num_bounds;
355   /* Most recently added IndexBound's range number */
356   Uint32 m_previous_range_num;
357 
358   /* Old Scan API range information
359    * List of RecAttr structures containing OldApiScanRangeDefinition
360    * structures
361    * currentRangeOldApi is range currently being defined (if any)
362    * Once defined (end_of_bound() / execute()) they are added to
363    * the list between first/lastRangeOldApi
364    */
365   NdbRecAttr* firstRangeOldApi;
366   NdbRecAttr* lastRangeOldApi;
367   NdbRecAttr* currentRangeOldApi;
368 
369   friend struct Ndb_free_list_t<NdbIndexScanOperation>;
370 
371 private:
372   NdbIndexScanOperation(const NdbIndexScanOperation&); // Not impl.
373   NdbIndexScanOperation&operator=(const NdbIndexScanOperation&);
374 };
375 
376 inline
377 int
setBound(const char * attr,int type,const void * value,Uint32 len)378 NdbIndexScanOperation::setBound(const char* attr, int type, const void* value,
379                                 Uint32 len)
380 {
381   (void)len;  // unused
382   return setBound(attr, type, value);
383 }
384 
385 inline
386 int
setBound(Uint32 anAttrId,int type,const void * value,Uint32 len)387 NdbIndexScanOperation::setBound(Uint32 anAttrId, int type, const void* value,
388                                 Uint32 len)
389 {
390   (void)len;  // unused
391   return setBound(anAttrId, type, value);
392 }
393 
394 /**
395  *   Compare keys of  the current records of two NdbReceiver objects.
396  * @param r1 holds the first record to compare.
397  * @param r2 holds the second record to compare.
398  * @param key_record specifies the keys to compare.
399  * @param result_record specifies the format of full records.
400  * @param descending if true, descending sort order is to be used.
401  * @param read_range_no if true, range numbers will first be compared, and then keys if range numbers are the same for both records.
402  * @return -1 if r1<r2, 0 if r1=r2, 1 if r1> r2 (reversed when using 'descending').
403  **/
404 int compare_ndbrecord(const NdbReceiver *r1,
405                       const NdbReceiver *r2,
406                       const NdbRecord *key_record,
407                       const NdbRecord *result_record,
408                       bool descending,
409                       bool read_range_no);
410 #endif
411