1 /*
2    Copyright (c) 2004, 2020, 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 NdbIndexScanOperation_H
26 #define NdbIndexScanOperation_H
27 
28 #include "NdbScanOperation.hpp"
29 
30 /**
31  * @class NdbIndexScanOperation
32  * @brief Class of scan operations for use to scan ordered index
33  */
34 class NdbIndexScanOperation : public NdbScanOperation {
35 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
36   friend class Ndb;
37   friend class NdbTransaction;
38   friend class NdbResultSet;
39   friend class NdbOperation;
40   friend class NdbScanOperation;
41   friend class NdbIndexStat;
42 #endif
43 
44 public:
45   /**
46    * readTuples using ordered index
47    * This method is used to specify details for an old Api Index Scan
48    * operation.
49    *
50    * @param lock_mode Lock mode
51    * @param scan_flags see @ref ScanFlag
52    * @param parallel No of fragments to scan in parallel (0=max)
53    */
54   virtual int readTuples(LockMode lock_mode = LM_Read,
55                          Uint32 scan_flags = 0,
56 			 Uint32 parallel = 0,
57 			 Uint32 batch = 0);
58 
59 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
60   /**
61    * readTuples using ordered index
62    *
63    * @param lock_mode Lock mode
64    * @param batch     No of rows to fetch from each fragment at a time
65    * @param parallel  No of fragments to scan in parallel
66    * @param order_by  Order result set in index order
67    * @param order_desc Order descending, ignored unless order_by
68    * @param read_range_no Enable reading of range no using @ref get_range_no
69    * @returns 0 for success and -1 for failure
70    * @see NdbScanOperation::readTuples
71    */
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)72   inline int readTuples(LockMode lock_mode,
73                         Uint32 batch,
74                         Uint32 parallel,
75                         bool order_by,
76                         bool order_desc = false,
77                         bool read_range_no = false,
78 			bool keyinfo = false,
79 			bool multi_range = false) {
80     Uint32 scan_flags =
81       (SF_OrderBy & -(Int32)order_by) |
82       (SF_Descending & -(Int32)order_desc) |
83       (SF_ReadRangeNo & -(Int32)read_range_no) |
84       (SF_KeyInfo & -(Int32)keyinfo) |
85       (SF_MultiRange & -(Int32)multi_range);
86 
87     return readTuples(lock_mode, scan_flags, parallel, batch);
88   }
89 #endif
90 
91   /**
92    * Type of ordered index key bound.  The values (0-4) will not change
93    * and can be used explicitly (e.g. they could be computed).
94    */
95   enum BoundType {
96     BoundLE = 0,        ///< lower bound
97     BoundLT = 1,        ///< lower bound, strict
98     BoundGE = 2,        ///< upper bound
99     BoundGT = 3,        ///< upper bound, strict
100     BoundEQ = 4         ///< equality
101   };
102 
103   /* Maximum number of ranges that can be supplied to a single
104    * NdbIndexScanOperation
105    */
106   enum {
107     MaxRangeNo= 0xfff
108   };
109 
110   /**
111    * Define bound on index key in range scan - old Api.
112    *
113    * Each index key can have lower and/or upper bound.  Setting the key
114    * equal to a value defines both upper and lower bounds.  The bounds
115    * can be defined in any order.  Conflicting definitions is an error.
116    *
117    * For equality, it is better to use BoundEQ instead of the equivalent
118    * pair of BoundLE and BoundGE.  This is especially true when table
119    * partition key is an initial part of the index key.
120    *
121    * The sets of lower and upper bounds must be on initial sequences of
122    * index keys.  All but possibly the last bound must be non-strict.
123    * So "a >= 2 and b > 3" is ok but "a > 2 and b >= 3" is not.
124    *
125    * The scan may currently return tuples for which the bounds are not
126    * satisfied.  For example, "a <= 2 and b <= 3" scans the index up to
127    * (a=2, b=3) but also returns any (a=1, b=4).
128    *
129    * NULL is treated like a normal value which is less than any not-NULL
130    * value and equal to another NULL value.  To compare against NULL use
131    * setBound with null pointer (0).
132    *
133    * An index stores also all-NULL keys.  Doing index scan with empty
134    * bound set returns all table tuples.
135    *
136    * @param attr        Attribute name, alternatively:
137    * @param type        Type of bound
138    * @param value       Pointer to bound value, 0 for NULL
139    * @return            0 if successful otherwise -1
140    *
141    * @note See comment under equal() about data format and length.
142    * @note See the two parameter setBound variant for use with NdbRecord
143    */
144 #ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
145   int setBound(const char* attr, int type, const void* value, Uint32 len);
146 #endif
147   int setBound(const char* attr, int type, const void* value);
148 
149   /**
150    * Define bound on index key in range scan using index column id.
151    * See the other setBound() method for details.
152    */
153 #ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
154   int setBound(Uint32 anAttrId, int type, const void* aValue, Uint32 len);
155 #endif
156   int setBound(Uint32 anAttrId, int type, const void* aValue);
157 
158   /**
159    * This method is called to separate sets of bounds (ranges) when
160    * defining an Index Scan with multiple ranges
161    * It can only be used with scans defined using the SF_MultiRange
162    * scan flag.
163    * For NdbRecord, ranges are specified using the IndexBound structure
164    * and the setBound() API.
165    * If an index scan has more than one range then end_of_bound must be
166    * called after every range, including the last.
167    * If the SF_ReadRangeNo flag is set then the range_no supplied when
168    * the range is defined will be associated with each row returned from
169    * that range.  This can be obtained by calling get_range_no().
170    * If SF_ReadRangeNo and SF_OrderBy flags are provided then range_no
171    * values must be strictly increasing (i.e. starting at zero and
172    * getting larger by 1 for each range specified).  This is to ensure
173    * that rows are returned in order.
174    */
175   int end_of_bound(Uint32 range_no= 0);
176 
177   /**
178    * Return range number for current row, as defined in the IndexBound
179    * structure used when the scan was defined.
180    * Only available if the SF_ReadRangeNo and SF_MultiRange flags were
181    * set in the ScanOptions::scan_flags structure passed to scanIndex().
182    */
183   int get_range_no();
184 
185   /* Structure used to describe index scan bounds, for NdbRecord scans. */
186   struct IndexBound {
187     /* Row containing lower bound, or NULL for scan from the start. */
188     const char *low_key;
189     /* Number of columns in lower bound, for bounding by partial prefix. */
190     Uint32 low_key_count;
191     /* True for less-than-or-equal, false for strictly less-than. */
192     bool low_inclusive;
193     /* Row containing upper bound, or NULL for scan to the end. */
194     const char * high_key;
195     /* Number of columns in upper bound, for bounding by partial prefix. */
196     Uint32 high_key_count;
197     /* True for greater-than-or-equal, false for strictly greater-than. */
198     bool high_inclusive;
199     /*
200       Value to identify this bound, may be read with get_range_no().
201       Must be <= MaxRangeNo (set to zero if not using range_no).
202       Note that for ordered scans, the range_no must be strictly increasing
203       for each range, or the result set will not be sorted correctly.
204     */
205     Uint32 range_no;
206   };
207 
208   /**
209    * Add a range to an NdbRecord defined Index scan
210    *
211    * This method is called to add a range to an IndexScan operation
212    * which has been defined with a call to NdbTransaction::scanIndex().
213    * To add more than one range, the index scan operation must have been
214    * defined with the the SF_MultiRange flag set.
215    *
216    * Where multiple numbered ranges are defined with multiple calls to
217    * setBound, and the scan is ordered, the range number for each range
218    * must be larger than the range number for the previously defined range.
219    *
220    * When the application knows that rows in-range will only be found in
221    * a particular partition, a PartitionSpecification can be supplied.
222    * This may be used to limit the scan to a single partition, improving
223    * system efficiency
224    * The sizeOfPartInfo parameter should be set to the
225    * sizeof(PartitionSpec) to enable backwards compatibility.
226    *
227    * @param key_record NdbRecord structure for the key the index is
228    *        defined on
229    * @param bound The bound to add
230    * @param partInfo Extra information to enable a reduced set of
231    *        partitions to be scanned.
232    * @param sizeOfPartInfo  should be set to the
233    *        sizeof(PartitionSpec) to enable backwards compatibility.
234    *
235    * @return 0 for Success, other for Failure.
236    */
237   int setBound(const NdbRecord *key_record,
238                const IndexBound& bound,
239                const Ndb::PartitionSpec* partInfo,
240                Uint32 sizeOfPartInfo= 0);
241   int setBound(const NdbRecord *key_record,
242                const IndexBound& bound);
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