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