1 /*
2 Copyright (C) 2004-2008 MySQL AB, 2009 Sun Microsystems, Inc.
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 * Is current scan sorted?
246 */
getSorted() const247 bool getSorted() const { return m_ordered; }
248
249 /**
250 * Is current scan sorted descending?
251 */
getDescending() const252 bool getDescending() const { return m_descending; }
253
254 private:
255 NdbIndexScanOperation(Ndb* aNdb);
256 virtual ~NdbIndexScanOperation();
257
258 int processIndexScanDefs(LockMode lm,
259 Uint32 scan_flags,
260 Uint32 parallel,
261 Uint32 batch);
262 int scanIndexImpl(const NdbRecord *key_record,
263 const NdbRecord *result_record,
264 NdbOperation::LockMode lock_mode,
265 const unsigned char *result_mask,
266 const NdbIndexScanOperation::IndexBound *bound,
267 const NdbScanOperation::ScanOptions *options,
268 Uint32 sizeOfOptions);
269
270 /* Structure used to collect information about an IndexBound
271 * as it is provided by the old Api setBound() calls
272 */
273 public:
274 struct OldApiBoundInfo
275 {
276 Uint32 highestKey;
277 bool highestSoFarIsStrict;
278 Uint32 keysPresentBitmap;
279 char* key;
280 };
281
282 private:
283 struct OldApiScanRangeDefinition
284 {
285 /* OldApiBoundInfo used during definition
286 * IndexBound used once bound defined
287 * Todo : For heavy old Api use, consider splitting
288 * to allow NdbRecAttr use without malloc
289 */
290 union {
291 struct {
292 OldApiBoundInfo lowBound;
293 OldApiBoundInfo highBound;
294 } oldBound;
295
296 IndexBound ib;
297 };
298 /* Space for key bounds
299 * Low bound from offset 0
300 * High bound from offset key_record->m_row_size
301 */
302 char space[1];
303 };
304
305 int setBoundHelperOldApi(OldApiBoundInfo& boundInfo,
306 Uint32 maxKeyRecordBytes,
307 Uint32 index_attrId,
308 Uint32 valueLen,
309 bool inclusive,
310 Uint32 byteOffset,
311 Uint32 nullbit_byte_offset,
312 Uint32 nullbit_bit_in_byte,
313 const void *aValue);
314
315 int setBound(const NdbColumnImpl*, int type, const void* aValue);
316 int buildIndexBoundOldApi(int range_no);
317 const IndexBound* getIndexBoundFromRecAttr(NdbRecAttr* recAttr);
318 void releaseIndexBoundsOldApi();
319 int ndbrecord_insert_bound(const NdbRecord *key_record,
320 Uint32 column_index,
321 const char *row,
322 Uint32 bound_type,
323 Uint32*& firstWordOfBound);
324 int insert_open_bound(const NdbRecord* key_record,
325 Uint32*& firstWordOfBound);
326
327 virtual int equal_impl(const NdbColumnImpl*, const char*);
328 virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char*);
329
330 int getDistKeyFromRange(const NdbRecord* key_record,
331 const NdbRecord* result_record,
332 const char* row,
333 Uint32* distKey);
334 void fix_get_values();
335 int next_result_ordered(bool fetchAllowed, bool forceSend = false);
336 int next_result_ordered_ndbrecord(const char * & out_row,
337 bool fetchAllowed,
338 bool forceSend);
339 void ordered_insert_receiver(Uint32 start, NdbReceiver *receiver);
340 int ordered_send_scan_wait_for_all(bool forceSend);
341 int send_next_scan_ordered(Uint32 idx);
342 int compare(Uint32 key, Uint32 cols, const NdbReceiver*, const NdbReceiver*);
343 Uint32 m_sort_columns;
344
345 /* Number of IndexBounds for this scan (NdbRecord only) */
346 Uint32 m_num_bounds;
347 /* Most recently added IndexBound's range number */
348 Uint32 m_previous_range_num;
349
350 /* Old Scan API range information
351 * List of RecAttr structures containing OldApiScanRangeDefinition
352 * structures
353 * currentRangeOldApi is range currently being defined (if any)
354 * Once defined (end_of_bound() / execute()) they are added to
355 * the list between first/lastRangeOldApi
356 */
357 NdbRecAttr* firstRangeOldApi;
358 NdbRecAttr* lastRangeOldApi;
359 NdbRecAttr* currentRangeOldApi;
360
361 friend struct Ndb_free_list_t<NdbIndexScanOperation>;
362
363 private:
364 NdbIndexScanOperation(const NdbIndexScanOperation&); // Not impl.
365 NdbIndexScanOperation&operator=(const NdbIndexScanOperation&);
366 };
367
368 inline
369 int
setBound(const char * attr,int type,const void * value,Uint32 len)370 NdbIndexScanOperation::setBound(const char* attr, int type, const void* value,
371 Uint32 len)
372 {
373 (void)len; // unused
374 return setBound(attr, type, value);
375 }
376
377 inline
378 int
setBound(Uint32 anAttrId,int type,const void * value,Uint32 len)379 NdbIndexScanOperation::setBound(Uint32 anAttrId, int type, const void* value,
380 Uint32 len)
381 {
382 (void)len; // unused
383 return setBound(anAttrId, type, value);
384 }
385
386 /**
387 * Compare keys of the current records of two NdbReceiver objects.
388 * @param r1 holds the first record to compare.
389 * @param r2 holds the second record to compare.
390 * @param key_record specifies the keys to compare.
391 * @param result_record specifies the format of full records.
392 * @param descending if true, descending sort order is to be used.
393 * @param read_range_no if true, range numbers will first be compared, and then keys if range numbers are the same for both records.
394 * @return -1 if r1<r2, 0 if r1=r2, 1 if r1> r2 (reversed when using 'descending').
395 **/
396 int compare_ndbrecord(const NdbReceiver *r1,
397 const NdbReceiver *r2,
398 const NdbRecord *key_record,
399 const NdbRecord *result_record,
400 bool descending,
401 bool read_range_no);
402 #endif
403