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