1 /*
2 Copyright (c) 2011, 2014 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 #include <ndb_global.h>
26 #include <NdbDictionary.hpp>
27 #include "NdbIndexScanOperation.hpp"
28 #include "NdbQueryBuilder.hpp"
29 #include "NdbQueryBuilderImpl.hpp"
30 #include <Vector.hpp>
31 #include "signaldata/QueryTree.hpp"
32
33 #include "NdbDictionaryImpl.hpp"
34 #include <NdbRecord.hpp>
35 #include "AttributeHeader.hpp"
36 #include "NdbOut.hpp"
37 #include <NdbInterpretedCode.hpp>
38
39 /**
40 * Implementation of all QueryBuilder objects are hidden from
41 * both the API interface and other internals in the NDBAPI using the
42 * pimpl idiom.
43 *
44 * The object hierarch visible through the interface has its 'Impl'
45 * counterparts inside this module. Some classes are
46 * even subclassed further as part of the implementation.
47 * (Particular the ConstOperant in order to implement multiple datatypes)
48 *
49 * In order to avoid allocating both an interface object and its particular
50 * Impl object, all 'final' Impl objects 'has a' interface object
51 * which is accessible through the virtual method ::getInterface.
52 *
53 * ::getImpl() methods has been defined for convenient access
54 * to all available Impl classes.
55 *
56 */
57
58 // For debugging purposes. Enable to print query tree graph to ndbout.
59 static const bool doPrintQueryTree = false;
60
61 /* Various error codes that are not specific to NdbQuery. */
62 static const int Err_MemoryAlloc = 4000;
63 static const int Err_FunctionNotImplemented = 4003;
64 static const int Err_UnknownColumn = 4004;
65 static const int Err_FinaliseNotCalled = 4519;
66
67 static void
setErrorCode(NdbQueryBuilderImpl * qb,int aErrorCode)68 setErrorCode(NdbQueryBuilderImpl* qb, int aErrorCode)
69 { qb->setErrorCode(aErrorCode);
70 }
71
72 static void
setErrorCode(NdbQueryBuilder * qb,int aErrorCode)73 setErrorCode(NdbQueryBuilder* qb, int aErrorCode)
74 { qb->getImpl().setErrorCode(aErrorCode);
75 }
76
77
78 //////////////////////////////////////////////////////////////////
79 // Convenient macro for returning specific errorcodes if
80 // 'cond' does not evaluate to true.
81 //////////////////////////////////////////////////////////////////
82 #define returnErrIf(cond,err) \
83 if (unlikely((cond))) \
84 { ::setErrorCode(this,err); \
85 return NULL; \
86 }
87
88
89 //////////////////////////////////////////////
90 // Implementation of NdbQueryOperand interface
91 //
92 // The common baseclass 'class NdbQueryOperandImpl',
93 // and its 'const', 'linked' and 'param' subclasses are
94 // defined in "NdbQueryBuilderImpl.hpp"
95 // The 'const' operand subclass is a pure virtual baseclass
96 // which has different type specific subclasses defined below:
97 //////////////////////////////////////////////////////////////
98
99 //////////////////////////////////////////////////
100 // Implements different const datatypes by further
101 // subclassing of the baseclass NdbConstOperandImpl.
102 //////////////////////////////////////////////////
103 class NdbInt64ConstOperandImpl : public NdbConstOperandImpl
104 {
105 public:
NdbInt64ConstOperandImpl(Int64 value)106 explicit NdbInt64ConstOperandImpl (Int64 value) :
107 NdbConstOperandImpl(),
108 m_value(value) {}
109
110 private:
111 int convertInt8();
112 int convertUint8();
113 int convertInt16();
114 int convertUint16();
115 int convertInt24();
116 int convertUint24();
117 int convertInt32();
118 int convertUint32();
119 int convertInt64();
120 int convertUint64();
121
122 const Int64 m_value;
123 };
124
125 class NdbDoubleConstOperandImpl : public NdbConstOperandImpl
126 {
127 public:
NdbDoubleConstOperandImpl(double value)128 explicit NdbDoubleConstOperandImpl (double value) :
129 NdbConstOperandImpl(),
130 m_value(value) {}
131
132 private:
133 int convertDouble();
134 int convertFloat();
135 private:
136 const double m_value;
137 };
138
139 class NdbCharConstOperandImpl : public NdbConstOperandImpl
140 {
141 public:
NdbCharConstOperandImpl(const char * value)142 explicit NdbCharConstOperandImpl (const char* value) :
143 NdbConstOperandImpl(), m_value(value) {}
144
145 private:
146 int convertChar();
147 int convertVChar();
148 //int convertLVChar();
149 private:
150 const char* const m_value;
151 };
152
153 class NdbGenericConstOperandImpl : public NdbConstOperandImpl
154 {
155 public:
NdbGenericConstOperandImpl(const void * value,Uint32 len)156 explicit NdbGenericConstOperandImpl (const void* value,
157 Uint32 len)
158 : NdbConstOperandImpl(),
159 m_value(value),
160 m_len(len)
161 {}
162
163 private:
164 int convert2ColumnType();
165
166 const void* const m_value;
167 const Uint32 m_len;
168 };
169
170 ////////////////////////////////////////////////
171 // Implementation of NdbQueryOperation interface
172 ////////////////////////////////////////////////
173
174 // Common Baseclass 'class NdbQueryOperationDefImpl' is
175 // defined in "NdbQueryBuilderImpl.hpp"
176
177 class NdbQueryLookupOperationDefImpl : public NdbQueryOperationDefImpl
178 {
179 friend class NdbQueryBuilder; // Allow privat access from builder interface
180
181 public:
getKeyOperands() const182 virtual const NdbQueryOperandImpl* const* getKeyOperands() const
183 { return m_keys; }
184
185 protected:
186
187 explicit NdbQueryLookupOperationDefImpl (
188 const NdbTableImpl& table,
189 const NdbQueryOperand* const keys[],
190 const NdbQueryOptionsImpl& options,
191 const char* ident,
192 Uint32 opNo,
193 Uint32 internalOpNo,
194 int& error);
195
getInterface() const196 virtual const NdbQueryLookupOperationDef& getInterface() const
197 { return m_interface; }
198
199 // Append pattern for creating lookup key to serialized code
200 Uint32 appendKeyPattern(Uint32Buffer& serializedDef) const;
201
isScanOperation() const202 virtual bool isScanOperation() const
203 { return false; }
204
205 protected:
206 NdbQueryLookupOperationDef m_interface;
207 NdbQueryOperandImpl* m_keys[MAX_ATTRIBUTES_IN_INDEX+1];
208
209 }; // class NdbQueryLookupOperationDefImpl
210
211 class NdbQueryPKLookupOperationDefImpl : public NdbQueryLookupOperationDefImpl
212 {
213 friend class NdbQueryBuilder; // Allow privat access from builder interface
214
215 public:
216 virtual int serializeOperation(Uint32Buffer& serializedDef);
217
218 private:
219
NdbQueryPKLookupOperationDefImpl(const NdbTableImpl & table,const NdbQueryOperand * const keys[],const NdbQueryOptionsImpl & options,const char * ident,Uint32 opNo,Uint32 internalOpNo,int & error)220 explicit NdbQueryPKLookupOperationDefImpl (
221 const NdbTableImpl& table,
222 const NdbQueryOperand* const keys[],
223 const NdbQueryOptionsImpl& options,
224 const char* ident,
225 Uint32 opNo,
226 Uint32 internalOpNo,
227 int& error)
228 : NdbQueryLookupOperationDefImpl(table, keys, options, ident, opNo,
229 internalOpNo, error)
230 {}
231
getType() const232 virtual NdbQueryOperationDef::Type getType() const
233 { return NdbQueryOperationDef::PrimaryKeyAccess; }
234
235 }; // class NdbQueryPKLookupOperationDefImpl
236
237
238 class NdbQueryIndexOperationDefImpl : public NdbQueryLookupOperationDefImpl
239 {
240 friend class NdbQueryBuilder; // Allow privat access from builder interface
241
242 public:
getIndex() const243 virtual const NdbIndexImpl* getIndex() const
244 { return &m_index; }
245
246 virtual int serializeOperation(Uint32Buffer& serializedDef);
247
248 private:
249
NdbQueryIndexOperationDefImpl(const NdbIndexImpl & index,const NdbTableImpl & table,const NdbQueryOperand * const keys[],const NdbQueryOptionsImpl & options,const char * ident,Uint32 opNo,Uint32 internalOpNo,int & error)250 explicit NdbQueryIndexOperationDefImpl (
251 const NdbIndexImpl& index,
252 const NdbTableImpl& table,
253 const NdbQueryOperand* const keys[],
254 const NdbQueryOptionsImpl& options,
255 const char* ident,
256 Uint32 opNo,
257 Uint32 internalOpNo,
258 int& error)
259 // Add 1 to 'id' since index lookup is serialized as two operations.
260 : NdbQueryLookupOperationDefImpl(table, keys, options, ident, opNo,
261 internalOpNo+1, error),
262 m_index(index)
263 {}
264
getType() const265 virtual NdbQueryOperationDef::Type getType() const
266 { return NdbQueryOperationDef::UniqueIndexAccess; }
267
268 private:
269 const NdbIndexImpl& m_index;
270
271 }; // class NdbQueryIndexOperationDefImpl
272
273
274 class NdbQueryTableScanOperationDefImpl : public NdbQueryScanOperationDefImpl
275 {
276 friend class NdbQueryBuilder; // Allow privat access from builder interface
277
278 public:
279 virtual int serializeOperation(Uint32Buffer& serializedDef);
280
getInterface() const281 virtual const NdbQueryTableScanOperationDef& getInterface() const
282 { return m_interface; }
283
getType() const284 virtual NdbQueryOperationDef::Type getType() const
285 { return NdbQueryOperationDef::TableScan; }
286
287 private:
288
NdbQueryTableScanOperationDefImpl(const NdbTableImpl & table,const NdbQueryOptionsImpl & options,const char * ident,Uint32 opNo,Uint32 internalOpNo,int & error)289 explicit NdbQueryTableScanOperationDefImpl (
290 const NdbTableImpl& table,
291 const NdbQueryOptionsImpl& options,
292 const char* ident,
293 Uint32 opNo,
294 Uint32 internalOpNo,
295 int& error)
296 : NdbQueryScanOperationDefImpl(table, options, ident, opNo,
297 internalOpNo, error),
298 m_interface(*this)
299 {}
300
301 NdbQueryTableScanOperationDef m_interface;
302
303 }; // class NdbQueryTableScanOperationDefImpl
304
305
306
307
308 ///////////////////////////////////////////////////
309 /////// End 'Impl' class declarations /////////////
310 ///////////////////////////////////////////////////
311
NdbQueryDef(NdbQueryDefImpl & impl)312 NdbQueryDef::NdbQueryDef(NdbQueryDefImpl& impl) : m_impl(impl)
313 {}
~NdbQueryDef()314 NdbQueryDef::~NdbQueryDef()
315 {}
316
317 Uint32
getNoOfOperations() const318 NdbQueryDef::getNoOfOperations() const
319 { return m_impl.getNoOfOperations();
320 }
321
322 const NdbQueryOperationDef*
getQueryOperation(Uint32 index) const323 NdbQueryDef::getQueryOperation(Uint32 index) const
324 { return &m_impl.getQueryOperation(index).getInterface();
325 }
326
327 const NdbQueryOperationDef*
getQueryOperation(const char * ident) const328 NdbQueryDef::getQueryOperation(const char* ident) const
329 { const NdbQueryOperationDefImpl *opDef = m_impl.getQueryOperation(ident);
330 return (opDef!=NULL) ? &opDef->getInterface() : NULL;
331 }
332
333 bool
isScanQuery() const334 NdbQueryDef::isScanQuery() const
335 { return m_impl.isScanQuery();
336 }
337
338 NdbQueryDef::QueryType
getQueryType() const339 NdbQueryDef::getQueryType() const
340 { return m_impl.getQueryType();
341 }
342
343 NdbQueryDefImpl&
getImpl() const344 NdbQueryDef::getImpl() const{
345 return m_impl;
346 }
347
348 void
destroy() const349 NdbQueryDef::destroy() const
350 {
351 delete &getImpl();
352 }
353
354 void
print() const355 NdbQueryDef::print() const
356 {
357 m_impl.getQueryOperation(0U)
358 .printTree(0, NdbQueryOperationDefImpl::SiblingMask());
359 }
360
361 /*************************************************************************
362 * Glue layer between NdbQueryOperand interface and its Impl'ementation.
363 ************************************************************************/
364
NdbQueryOperand(NdbQueryOperandImpl & impl)365 NdbQueryOperand::NdbQueryOperand(NdbQueryOperandImpl& impl) : m_impl(impl)
366 {}
NdbConstOperand(NdbQueryOperandImpl & impl)367 NdbConstOperand::NdbConstOperand(NdbQueryOperandImpl& impl) : NdbQueryOperand(impl)
368 {}
NdbParamOperand(NdbQueryOperandImpl & impl)369 NdbParamOperand::NdbParamOperand(NdbQueryOperandImpl& impl) : NdbQueryOperand(impl)
370 {}
NdbLinkedOperand(NdbQueryOperandImpl & impl)371 NdbLinkedOperand::NdbLinkedOperand(NdbQueryOperandImpl& impl) : NdbQueryOperand(impl)
372 {}
373
374 // D'tors
~NdbQueryOperand()375 NdbQueryOperand::~NdbQueryOperand()
376 {}
~NdbConstOperand()377 NdbConstOperand::~NdbConstOperand()
378 {}
~NdbParamOperand()379 NdbParamOperand::~NdbParamOperand()
380 {}
~NdbLinkedOperand()381 NdbLinkedOperand::~NdbLinkedOperand()
382 {}
383
384 /**
385 * Get'ers for NdbQueryOperand...Impl object.
386 * Functions overridden to supply 'impl' casted to the correct '...OperandImpl' type
387 * for each available interface class.
388 */
389 inline NdbQueryOperandImpl&
getImpl() const390 NdbQueryOperand::getImpl() const
391 { return m_impl;
392 }
393 inline static
getImpl(const NdbQueryOperand & op)394 NdbQueryOperandImpl& getImpl(const NdbQueryOperand& op)
395 { return op.getImpl();
396 }
397 inline static
getImpl(const NdbConstOperand & op)398 NdbConstOperandImpl& getImpl(const NdbConstOperand& op)
399 { return static_cast<NdbConstOperandImpl&>(op.getImpl());
400 }
401 inline static
getImpl(const NdbParamOperand & op)402 NdbParamOperandImpl& getImpl(const NdbParamOperand& op)
403 { return static_cast<NdbParamOperandImpl&>(op.getImpl());
404 }
405 inline static
getImpl(const NdbLinkedOperand & op)406 NdbLinkedOperandImpl& getImpl(const NdbLinkedOperand& op)
407 { return static_cast<NdbLinkedOperandImpl&>(op.getImpl());
408 }
409
410 /**
411 * BEWARE: Return 'NULL' Until the operand has been bound to an operation.
412 */
413 const NdbDictionary::Column*
getColumn() const414 NdbQueryOperand::getColumn() const
415 {
416 return ::getImpl(*this).getColumn();
417 }
418
419 const char*
getName() const420 NdbParamOperand::getName() const
421 {
422 return ::getImpl(*this).getName();
423 }
424
425 Uint32
getEnum() const426 NdbParamOperand::getEnum() const
427 {
428 return ::getImpl(*this).getParamIx();
429 }
430
431 /****************************************************************************
432 * Implementation of NdbQueryOptions.
433 * Because of the simplicity of this class, the implementation has *not*
434 * been split into methods in the Impl class with a glue layer to the
435 * outside interface.
436 ****************************************************************************/
437 static NdbQueryOptionsImpl defaultOptions;
438
NdbQueryOptions()439 NdbQueryOptions::NdbQueryOptions()
440 : m_pimpl(&defaultOptions)
441 {}
442
~NdbQueryOptions()443 NdbQueryOptions::~NdbQueryOptions()
444 {
445 if (m_pimpl!=&defaultOptions)
446 delete m_pimpl;
447 }
448
449 const NdbQueryOptionsImpl&
getImpl() const450 NdbQueryOptions::getImpl() const
451 {
452 return *m_pimpl;
453 }
454
455 int
setOrdering(ScanOrdering ordering)456 NdbQueryOptions::setOrdering(ScanOrdering ordering)
457 {
458 if (m_pimpl==&defaultOptions)
459 {
460 m_pimpl = new NdbQueryOptionsImpl;
461 if (unlikely(m_pimpl==0))
462 {
463 return Err_MemoryAlloc;
464 }
465 }
466 m_pimpl->m_scanOrder = ordering;
467 return 0;
468 }
469
470 int
setMatchType(MatchType matchType)471 NdbQueryOptions::setMatchType(MatchType matchType)
472 {
473 if (m_pimpl==&defaultOptions)
474 {
475 m_pimpl = new NdbQueryOptionsImpl;
476 if (unlikely(m_pimpl==0))
477 {
478 return Err_MemoryAlloc;
479 }
480 }
481 m_pimpl->m_matchType = matchType;
482 return 0;
483 }
484
485 int
setParent(const NdbQueryOperationDef * parent)486 NdbQueryOptions::setParent(const NdbQueryOperationDef* parent)
487 {
488 if (m_pimpl==&defaultOptions)
489 {
490 m_pimpl = new NdbQueryOptionsImpl;
491 if (unlikely(m_pimpl==0))
492 {
493 return Err_MemoryAlloc;
494 }
495 }
496 m_pimpl->m_parent = &parent->getImpl();
497 return 0;
498 }
499
500 int
setInterpretedCode(const NdbInterpretedCode & code)501 NdbQueryOptions::setInterpretedCode(const NdbInterpretedCode& code)
502 {
503 if (m_pimpl==&defaultOptions)
504 {
505 m_pimpl = new NdbQueryOptionsImpl;
506 if (unlikely(m_pimpl==0))
507 {
508 return Err_MemoryAlloc;
509 }
510 }
511 return m_pimpl->copyInterpretedCode(code);
512 }
513
514
~NdbQueryOptionsImpl()515 NdbQueryOptionsImpl::~NdbQueryOptionsImpl()
516 {
517 delete m_interpretedCode;
518 }
519
NdbQueryOptionsImpl(const NdbQueryOptionsImpl & src)520 NdbQueryOptionsImpl::NdbQueryOptionsImpl(const NdbQueryOptionsImpl& src)
521 : m_matchType(src.m_matchType),
522 m_scanOrder(src.m_scanOrder),
523 m_parent(src.m_parent),
524 m_interpretedCode(NULL)
525 {
526 if (src.m_interpretedCode)
527 {
528 copyInterpretedCode(*src.m_interpretedCode);
529 }
530 }
531
532 /*
533 * Make a deep copy, such that 'src' can be destroyed when this method
534 * returns.
535 */
536 int
copyInterpretedCode(const NdbInterpretedCode & src)537 NdbQueryOptionsImpl::copyInterpretedCode(const NdbInterpretedCode& src)
538 {
539 /* Check the program's finalised */
540 if (unlikely(!(src.m_flags & NdbInterpretedCode::Finalised)))
541 {
542 return Err_FinaliseNotCalled; // NdbInterpretedCode::finalise() not called.
543 }
544 if (src.m_instructions_length == 0)
545 {
546 return 0;
547 }
548
549 NdbInterpretedCode* interpretedCode = new NdbInterpretedCode();
550 if (unlikely(interpretedCode==NULL))
551 {
552 return Err_MemoryAlloc;
553 }
554
555 const int error = interpretedCode->copy(src);
556 if (unlikely(error))
557 {
558 delete interpretedCode;
559 return error;
560 }
561
562 /* Replace existing NdbInterpretedCode */
563 if (m_interpretedCode)
564 delete m_interpretedCode;
565
566 m_interpretedCode = interpretedCode;
567 return 0;
568 }
569
570
571 /****************************************************************************
572 * Glue layer between NdbQueryOperationDef interface and its Impl'ementation.
573 ****************************************************************************/
NdbQueryOperationDef(NdbQueryOperationDefImpl & impl)574 NdbQueryOperationDef::NdbQueryOperationDef(NdbQueryOperationDefImpl& impl) : m_impl(impl)
575 {}
NdbQueryLookupOperationDef(NdbQueryOperationDefImpl & impl)576 NdbQueryLookupOperationDef::NdbQueryLookupOperationDef(NdbQueryOperationDefImpl& impl) : NdbQueryOperationDef(impl)
577 {}
NdbQueryScanOperationDef(NdbQueryOperationDefImpl & impl)578 NdbQueryScanOperationDef::NdbQueryScanOperationDef(NdbQueryOperationDefImpl& impl) : NdbQueryOperationDef(impl)
579 {}
NdbQueryTableScanOperationDef(NdbQueryOperationDefImpl & impl)580 NdbQueryTableScanOperationDef::NdbQueryTableScanOperationDef(NdbQueryOperationDefImpl& impl) : NdbQueryScanOperationDef(impl)
581 {}
NdbQueryIndexScanOperationDef(NdbQueryOperationDefImpl & impl)582 NdbQueryIndexScanOperationDef::NdbQueryIndexScanOperationDef(NdbQueryOperationDefImpl& impl) : NdbQueryScanOperationDef(impl)
583 {}
584
585
586 // D'tors
~NdbQueryOperationDef()587 NdbQueryOperationDef::~NdbQueryOperationDef()
588 {}
~NdbQueryLookupOperationDef()589 NdbQueryLookupOperationDef::~NdbQueryLookupOperationDef()
590 {}
~NdbQueryScanOperationDef()591 NdbQueryScanOperationDef::~NdbQueryScanOperationDef()
592 {}
~NdbQueryTableScanOperationDef()593 NdbQueryTableScanOperationDef::~NdbQueryTableScanOperationDef()
594 {}
~NdbQueryIndexScanOperationDef()595 NdbQueryIndexScanOperationDef::~NdbQueryIndexScanOperationDef()
596 {}
597
~NdbQueryOperationDefImpl()598 NdbQueryOperationDefImpl::~NdbQueryOperationDefImpl()
599 {
600 // Unlink any parent and child refering this object
601 if (m_parent != NULL)
602 {
603 m_parent->removeChild(this);
604 }
605 for (Uint32 i = 0; i<m_children.size(); i++)
606 {
607 assert(m_children[i]->m_parent == this);
608 m_children[i]->m_parent = NULL;
609 }
610 }
611
612 /**
613 * Get'ers for QueryOperation...DefImpl object.
614 * Functions overridden to supply 'impl' casted to the correct '...DefImpl' type
615 * for each available interface class.
616 */
617 NdbQueryOperationDefImpl&
getImpl() const618 NdbQueryOperationDef::getImpl() const
619 { return m_impl;
620 }
621 inline static
getImpl(const NdbQueryOperationDef & op)622 NdbQueryOperationDefImpl& getImpl(const NdbQueryOperationDef& op)
623 { return op.getImpl();
624 }
625 inline static
getImpl(const NdbQueryLookupOperationDef & op)626 NdbQueryLookupOperationDefImpl& getImpl(const NdbQueryLookupOperationDef& op)
627 { return static_cast<NdbQueryLookupOperationDefImpl&>(op.getImpl());
628 }
629 inline static
getImpl(const NdbQueryTableScanOperationDef & op)630 NdbQueryTableScanOperationDefImpl& getImpl(const NdbQueryTableScanOperationDef& op)
631 { return static_cast<NdbQueryTableScanOperationDefImpl&>(op.getImpl());
632 }
633 inline static
getImpl(const NdbQueryIndexScanOperationDef & op)634 NdbQueryIndexScanOperationDefImpl& getImpl(const NdbQueryIndexScanOperationDef& op)
635 { return static_cast<NdbQueryIndexScanOperationDefImpl&>(op.getImpl());
636 }
637
638
639 Uint32
getOpNo() const640 NdbQueryOperationDef::getOpNo() const
641 {
642 return ::getImpl(*this).getOpNo();
643 }
644
645 Uint32
getNoOfParentOperations() const646 NdbQueryOperationDef::getNoOfParentOperations() const
647 {
648 return ::getImpl(*this).getNoOfParentOperations();
649 }
650
651 const NdbQueryOperationDef*
getParentOperation(Uint32 i) const652 NdbQueryOperationDef::getParentOperation(Uint32 i) const
653 {
654 return &::getImpl(*this).getParentOperation(i).getInterface();
655 }
656
657 Uint32
getNoOfChildOperations() const658 NdbQueryOperationDef::getNoOfChildOperations() const
659 {
660 return ::getImpl(*this).getNoOfChildOperations();
661 }
662
663 const NdbQueryOperationDef*
getChildOperation(Uint32 i) const664 NdbQueryOperationDef::getChildOperation(Uint32 i) const
665 {
666 return &::getImpl(*this).getChildOperation(i).getInterface();
667 }
668
669 const char*
getTypeName(Type type)670 NdbQueryOperationDef::getTypeName(Type type)
671 {
672 switch(type)
673 {
674 case PrimaryKeyAccess:
675 return "PrimaryKeyAccess";
676 case UniqueIndexAccess:
677 return "UniqueIndexAccess";
678 case TableScan:
679 return "TableScan";
680 case OrderedIndexScan:
681 return "OrderedIndexScan";
682 default:
683 return "<Invalid NdbQueryOperationDef::Type value>";
684 }
685 }
686
687
688 NdbQueryOperationDef::Type
getType() const689 NdbQueryOperationDef::getType() const
690 {
691 return ::getImpl(*this).getType();
692 }
693
694 const NdbDictionary::Table*
getTable() const695 NdbQueryOperationDef::getTable() const
696 {
697 return &::getImpl(*this).getTable();
698 }
699
700 const NdbDictionary::Index*
getIndex() const701 NdbQueryOperationDef::getIndex() const
702 {
703 return ::getImpl(*this).getIndex();
704 }
705
706 /*******************************************
707 * Implementation of NdbQueryBuilder factory
708 ******************************************/
709 // Static method.
create()710 NdbQueryBuilder* NdbQueryBuilder::create()
711 {
712 NdbQueryBuilderImpl* const impl = new NdbQueryBuilderImpl();
713 if (likely (impl != NULL))
714 {
715 if((!ndb_join_pushdown(ndbGetOwnVersion())))
716 {
717 /* The SPJ code is present in releases where the SPJ feature is
718 * not yet enabled.
719 */
720 impl->setErrorCode(Err_FunctionNotImplemented);
721 }
722 return &impl->m_interface;
723 }
724 else
725 {
726 return NULL;
727 }
728 }
729
destroy()730 void NdbQueryBuilder::destroy()
731 {
732 delete &m_impl;
733 }
734
NdbQueryBuilder(NdbQueryBuilderImpl & impl)735 NdbQueryBuilder::NdbQueryBuilder(NdbQueryBuilderImpl& impl)
736 : m_impl(impl)
737 {}
738
~NdbQueryBuilder()739 NdbQueryBuilder::~NdbQueryBuilder()
740 {}
741
742 inline NdbQueryBuilderImpl&
getImpl() const743 NdbQueryBuilder::getImpl() const
744 { return m_impl;
745 }
746
747 const NdbError&
getNdbError() const748 NdbQueryBuilder::getNdbError() const
749 {
750 return m_impl.getNdbError();
751 }
752
753 //////////////////////////////////////////////////
754 // Implements different const datatypes by further
755 // subclassing of NdbConstOperand.
756 /////////////////////////////////////////////////
757 NdbConstOperand*
constValue(const char * value)758 NdbQueryBuilder::constValue(const char* value)
759 {
760 returnErrIf(value==0,QRY_REQ_ARG_IS_NULL);
761 return static_cast<NdbConstOperand*>
762 (m_impl.addOperand(new NdbCharConstOperandImpl(value)));
763 }
764
765 NdbConstOperand*
constValue(const void * value,Uint32 len)766 NdbQueryBuilder::constValue(const void* value, Uint32 len)
767 {
768 returnErrIf(value == 0, QRY_REQ_ARG_IS_NULL);
769 return static_cast<NdbConstOperand*>
770 (m_impl.addOperand(new NdbGenericConstOperandImpl(value,len)));
771 }
772
773 NdbConstOperand*
constValue(Int32 value)774 NdbQueryBuilder::constValue(Int32 value)
775 {
776 return static_cast<NdbConstOperand*>
777 (m_impl.addOperand(new NdbInt64ConstOperandImpl(value)));
778 }
779
780 NdbConstOperand*
constValue(Uint32 value)781 NdbQueryBuilder::constValue(Uint32 value)
782 {
783 return static_cast<NdbConstOperand*>
784 (m_impl.addOperand(new NdbInt64ConstOperandImpl(value)));
785 }
786
787 NdbConstOperand*
constValue(Int64 value)788 NdbQueryBuilder::constValue(Int64 value)
789 {
790 return static_cast<NdbConstOperand*>
791 (m_impl.addOperand(new NdbInt64ConstOperandImpl(value)));
792 }
793
794 NdbConstOperand*
constValue(Uint64 value)795 NdbQueryBuilder::constValue(Uint64 value)
796 {
797 return static_cast<NdbConstOperand*>
798 (m_impl.addOperand(new NdbInt64ConstOperandImpl(value)));
799 }
800
801 NdbConstOperand*
constValue(double value)802 NdbQueryBuilder::constValue(double value)
803 {
804 return static_cast<NdbConstOperand*>
805 (m_impl.addOperand(new NdbDoubleConstOperandImpl(value)));
806 }
807
808 NdbParamOperand*
paramValue(const char * name)809 NdbQueryBuilder::paramValue(const char* name)
810 {
811 return static_cast<NdbParamOperand*>
812 (m_impl.addOperand(new NdbParamOperandImpl(name,getImpl().m_paramCnt++)));
813 }
814
815 NdbLinkedOperand*
linkedValue(const NdbQueryOperationDef * parent,const char * attr)816 NdbQueryBuilder::linkedValue(const NdbQueryOperationDef* parent, const char* attr)
817 {
818 // Required non-NULL arguments
819 returnErrIf(parent==0 || attr==0, QRY_REQ_ARG_IS_NULL);
820 NdbQueryOperationDefImpl& parentImpl = parent->getImpl();
821
822 // Parent should be a OperationDef contained in this query builder context
823 returnErrIf(!m_impl.contains(&parentImpl), QRY_UNKNOWN_PARENT);
824
825 // 'attr' should refer a column from the underlying table in parent:
826 const NdbColumnImpl* column = parentImpl.getTable().getColumn(attr);
827 returnErrIf(column==0, Err_UnknownColumn); // Unknown column
828
829 // Locate refered parrent column in parent operations SPJ projection list;
830 // Add if not already present
831 int error = 0;
832 Uint32 colIx = parentImpl.addColumnRef(column, error);
833 if (unlikely(error != 0))
834 {
835 m_impl.setErrorCode(error);
836 return NULL;
837 }
838
839 return static_cast<NdbLinkedOperand*>
840 (m_impl.addOperand(new NdbLinkedOperandImpl(parentImpl,colIx)));
841 }
842
843 // Check if there is at least one linked operand.
hasLinkedOperand(const NdbQueryOperand * const keys[])844 static bool hasLinkedOperand(const NdbQueryOperand* const keys[])
845 {
846 int i = 0;
847 while (keys[i] != NULL)
848 {
849 if (keys[i]->getImpl().getKind() == NdbQueryOperandImpl::Linked)
850 {
851 return true;
852 }
853 i++;
854 }
855 return false;
856 }
857
858 const NdbQueryLookupOperationDef*
readTuple(const NdbDictionary::Table * table,const NdbQueryOperand * const keys[],const NdbQueryOptions * options,const char * ident)859 NdbQueryBuilder::readTuple(const NdbDictionary::Table* table, // Primary key lookup
860 const NdbQueryOperand* const keys[], // Terminated by NULL element
861 const NdbQueryOptions* options,
862 const char* ident)
863 {
864 int i;
865 if (m_impl.hasError())
866 return NULL;
867
868 returnErrIf(table==0 || keys==0, QRY_REQ_ARG_IS_NULL);
869 // All operations but the first one must depend on some other operation.
870 returnErrIf(m_impl.m_operations.size() > 0 && !hasLinkedOperand(keys),
871 QRY_UNKNOWN_PARENT);
872
873 const NdbTableImpl& tableImpl = NdbTableImpl::getImpl(*table);
874
875 // All column values being part of primary key should be specified:
876 int keyfields = table->getNoOfPrimaryKeys();
877 int colcount = table->getNoOfColumns();
878
879 // Check: keys[] are specified for all fields in PK
880 for (i=0; i<keyfields; ++i)
881 {
882 // A 'Key' value is undefined
883 returnErrIf(keys[i]==NULL, QRY_TOO_FEW_KEY_VALUES);
884 }
885 // Check for propper NULL termination of keys[] spec
886 returnErrIf(keys[keyfields]!=NULL, QRY_TOO_MANY_KEY_VALUES);
887
888 int error = 0;
889 NdbQueryPKLookupOperationDefImpl* op =
890 new NdbQueryPKLookupOperationDefImpl(tableImpl,
891 keys,
892 options ? options->getImpl() : defaultOptions,
893 ident,
894 m_impl.m_operations.size(),
895 m_impl.getNextInternalOpNo(),
896 error);
897
898 returnErrIf(m_impl.takeOwnership(op)!=0, Err_MemoryAlloc);
899 returnErrIf(error!=0, error); // C'tor returned error, bailout
900
901 Uint32 keyindex = 0;
902 for (i=0; i<colcount; ++i)
903 {
904 const NdbColumnImpl *col = tableImpl.getColumn(i);
905 if (col->getPrimaryKey())
906 {
907 assert (keyindex==col->m_keyInfoPos);
908 int error = op->m_keys[col->m_keyInfoPos]->bindOperand(*col,*op);
909 returnErrIf(error!=0, error);
910
911 keyindex++;
912 if (keyindex >= static_cast<Uint32>(keyfields))
913 break; // Seen all PK fields
914 }
915 }
916
917 return &op->m_interface;
918 }
919
920
921 const NdbQueryLookupOperationDef*
readTuple(const NdbDictionary::Index * index,const NdbDictionary::Table * table,const NdbQueryOperand * const keys[],const NdbQueryOptions * options,const char * ident)922 NdbQueryBuilder::readTuple(const NdbDictionary::Index* index, // Unique key lookup w/ index
923 const NdbDictionary::Table* table, // Primary key lookup
924 const NdbQueryOperand* const keys[], // Terminated by NULL element
925 const NdbQueryOptions* options,
926 const char* ident)
927 {
928 int i;
929
930 if (m_impl.hasError())
931 return NULL;
932
933 returnErrIf(table==0 || index==0 || keys==0, QRY_REQ_ARG_IS_NULL);
934 // All operations but the first one must depend on some other operation.
935 returnErrIf(m_impl.m_operations.size() > 0 && !hasLinkedOperand(keys),
936 QRY_UNKNOWN_PARENT);
937
938 const NdbIndexImpl& indexImpl = NdbIndexImpl::getImpl(*index);
939 const NdbTableImpl& tableImpl = NdbTableImpl::getImpl(*table);
940
941 // TODO: Restrict to only table_version_major() mismatch?
942 returnErrIf(indexImpl.m_table_id
943 != static_cast<Uint32>(table->getObjectId()) ||
944 indexImpl.m_table_version
945 != static_cast<Uint32>(table->getObjectVersion()),
946 QRY_UNRELATED_INDEX);
947
948 // Only 'UNIQUE' indexes may be used for lookup operations:
949 returnErrIf(index->getType()!=NdbDictionary::Index::UniqueHashIndex,
950 QRY_WRONG_INDEX_TYPE);
951
952 // Check: keys[] are specified for all fields in 'index'
953 int inxfields = index->getNoOfColumns();
954 for (i=0; i<inxfields; ++i)
955 {
956 // A 'Key' value is undefined
957 returnErrIf(keys[i]==NULL, QRY_TOO_FEW_KEY_VALUES);
958 }
959 // Check for propper NULL termination of keys[] spec
960 returnErrIf(keys[inxfields]!=NULL, QRY_TOO_MANY_KEY_VALUES);
961
962 int error = 0;
963 NdbQueryIndexOperationDefImpl* op =
964 new NdbQueryIndexOperationDefImpl(indexImpl, tableImpl,
965 keys,
966 options ? options->getImpl() : defaultOptions,
967 ident,
968 m_impl.m_operations.size(),
969 m_impl.getNextInternalOpNo(),
970 error);
971
972 returnErrIf(m_impl.takeOwnership(op)!=0, Err_MemoryAlloc);
973 returnErrIf(error!=0, error); // C'tor returned error, bailout
974
975 // Bind to Column and check type compatibility
976 for (i=0; i<inxfields; ++i)
977 {
978 const NdbColumnImpl& col = NdbColumnImpl::getImpl(*indexImpl.getColumn(i));
979 assert (col.getColumnNo() == i);
980
981 error = keys[i]->getImpl().bindOperand(col,*op);
982 returnErrIf(error!=0, error);
983 }
984
985 return &op->m_interface;
986 }
987
988
989 const NdbQueryTableScanOperationDef*
scanTable(const NdbDictionary::Table * table,const NdbQueryOptions * options,const char * ident)990 NdbQueryBuilder::scanTable(const NdbDictionary::Table* table,
991 const NdbQueryOptions* options,
992 const char* ident)
993 {
994 if (m_impl.hasError())
995 return NULL;
996 returnErrIf(table==0, QRY_REQ_ARG_IS_NULL); // Required non-NULL arguments
997 /**
998 * A table scan does not depend on other operations, since there cannot be
999 * linked operands in a scan filter. Therefore, it must be the first
1000 * operation.
1001 */
1002 returnErrIf(m_impl.m_operations.size() > 0, QRY_UNKNOWN_PARENT);
1003
1004 int error = 0;
1005 NdbQueryTableScanOperationDefImpl* op =
1006 new NdbQueryTableScanOperationDefImpl(NdbTableImpl::getImpl(*table),
1007 options ? options->getImpl() : defaultOptions,
1008 ident,
1009 m_impl.m_operations.size(),
1010 m_impl.getNextInternalOpNo(),
1011 error);
1012
1013 returnErrIf(m_impl.takeOwnership(op)!=0, Err_MemoryAlloc);
1014 returnErrIf(error!=0, error); // C'tor returned error, bailout
1015
1016 return &op->m_interface;
1017 }
1018
1019
1020 const NdbQueryIndexScanOperationDef*
scanIndex(const NdbDictionary::Index * index,const NdbDictionary::Table * table,const NdbQueryIndexBound * bound,const NdbQueryOptions * options,const char * ident)1021 NdbQueryBuilder::scanIndex(const NdbDictionary::Index* index,
1022 const NdbDictionary::Table* table,
1023 const NdbQueryIndexBound* bound,
1024 const NdbQueryOptions* options,
1025 const char* ident)
1026 {
1027 if (m_impl.hasError())
1028 return NULL;
1029 // Required non-NULL arguments
1030 returnErrIf(table==0 || index==0, QRY_REQ_ARG_IS_NULL);
1031
1032 if (m_impl.m_operations.size() > 0)
1033 {
1034 // All operations but the first one must depend on some other operation.
1035 returnErrIf(bound == NULL ||
1036 (!hasLinkedOperand(bound->m_low) &&
1037 !hasLinkedOperand(bound->m_high)),
1038 QRY_UNKNOWN_PARENT);
1039
1040 // Scan with root lookup operation has not been implemented.
1041 returnErrIf(!m_impl.m_operations[0]->isScanOperation(),
1042 QRY_WRONG_OPERATION_TYPE);
1043
1044 if (options != NULL)
1045 {
1046 // A child scan should not be sorted.
1047 const NdbQueryOptions::ScanOrdering order =
1048 options->getImpl().getOrdering();
1049 returnErrIf(order == NdbQueryOptions::ScanOrdering_ascending ||
1050 order == NdbQueryOptions::ScanOrdering_descending,
1051 QRY_MULTIPLE_SCAN_SORTED);
1052 }
1053 }
1054
1055 const NdbIndexImpl& indexImpl = NdbIndexImpl::getImpl(*index);
1056 const NdbTableImpl& tableImpl = NdbTableImpl::getImpl(*table);
1057
1058 // TODO: Restrict to only table_version_major() mismatch?
1059 returnErrIf(indexImpl.m_table_id
1060 != static_cast<Uint32>(table->getObjectId()) ||
1061 indexImpl.m_table_version
1062 != static_cast<Uint32>(table->getObjectVersion()),
1063 QRY_UNRELATED_INDEX);
1064
1065 // Only ordered indexes may be used in scan operations:
1066 returnErrIf(index->getType()!=NdbDictionary::Index::OrderedIndex,
1067 QRY_WRONG_INDEX_TYPE);
1068
1069 int error = 0;
1070 NdbQueryIndexScanOperationDefImpl* op =
1071 new NdbQueryIndexScanOperationDefImpl(indexImpl, tableImpl,
1072 bound,
1073 options ? options->getImpl() : defaultOptions,
1074 ident,
1075 m_impl.m_operations.size(),
1076 m_impl.getNextInternalOpNo(),
1077 error);
1078
1079 returnErrIf(m_impl.takeOwnership(op)!=0, Err_MemoryAlloc);
1080 returnErrIf(error!=0, error); // C'tor returned error, bailout
1081
1082 returnErrIf(op->m_bound.lowKeys > indexImpl.getNoOfColumns() ||
1083 op->m_bound.highKeys > indexImpl.getNoOfColumns(),
1084 QRY_TOO_MANY_KEY_VALUES);
1085
1086 // Bind lowKeys, and if applicable, highKeys to the column being refered
1087 Uint32 i;
1088 for (i=0; i<op->m_bound.lowKeys; ++i)
1089 {
1090 const NdbColumnImpl& col = NdbColumnImpl::getImpl(*indexImpl.getColumn(i));
1091
1092 const int error = (i<op->m_bound.highKeys && op->m_bound.high[i]!=op->m_bound.low[i])
1093 ? op->m_bound.low[i]->bindOperand(col,*op) || op->m_bound.high[i]->bindOperand(col,*op)
1094 : op->m_bound.low[i]->bindOperand(col,*op);
1095
1096 returnErrIf(error!=0, error);
1097 }
1098
1099 // Bind any remaining highKeys past '#lowKeys'
1100 for (; i<op->m_bound.highKeys; ++i)
1101 {
1102 const NdbColumnImpl& col = NdbColumnImpl::getImpl(*indexImpl.getColumn(i));
1103 error = op->m_bound.high[i]->bindOperand(col,*op);
1104 returnErrIf(error!=0, error);
1105 }
1106
1107 return &op->m_interface;
1108 }
1109
1110 const NdbQueryDef*
prepare()1111 NdbQueryBuilder::prepare()
1112 {
1113 const NdbQueryDefImpl* def = m_impl.prepare();
1114 return (def) ? &def->getInterface() : NULL;
1115 }
1116
1117 ////////////////////////////////////////
1118 // The (hidden) Impl of NdbQueryBuilder
1119 ////////////////////////////////////////
1120
NdbQueryBuilderImpl()1121 NdbQueryBuilderImpl::NdbQueryBuilderImpl()
1122 : m_interface(*this),
1123 m_error(),
1124 m_operations(0),
1125 m_operands(0),
1126 m_paramCnt(0),
1127 m_hasError(false)
1128 {}
1129
~NdbQueryBuilderImpl()1130 NdbQueryBuilderImpl::~NdbQueryBuilderImpl()
1131 {
1132 // Delete all operand and operator in Vector's
1133 for (Uint32 i=0; i<m_operations.size(); ++i)
1134 {
1135 delete m_operations[i];
1136 }
1137 for (Uint32 i=0; i<m_operands.size(); ++i)
1138 {
1139 delete m_operands[i];
1140 }
1141 }
1142
setErrorCode(int aErrorCode)1143 void NdbQueryBuilderImpl::setErrorCode(int aErrorCode)
1144 {
1145 DBUG_ASSERT(aErrorCode != 0);
1146 m_error.code = aErrorCode;
1147 m_hasError = true;
1148 }
1149
1150 bool
contains(const NdbQueryOperationDefImpl * opDef)1151 NdbQueryBuilderImpl::contains(const NdbQueryOperationDefImpl* opDef)
1152 {
1153 for (Uint32 i=0; i<m_operations.size(); ++i)
1154 { if (m_operations[i] == opDef)
1155 return true;
1156 }
1157 return false;
1158 }
1159
1160
1161 const NdbQueryDefImpl*
prepare()1162 NdbQueryBuilderImpl::prepare()
1163 {
1164 if (hasError())
1165 {
1166 return NULL;
1167 }
1168 if (m_operations.size() == 0)
1169 {
1170 setErrorCode(QRY_HAS_ZERO_OPERATIONS);
1171 return NULL;
1172 }
1173
1174 int error;
1175 NdbQueryDefImpl* def = new NdbQueryDefImpl(m_operations, m_operands, error);
1176 m_operations.clear();
1177 m_operands.clear();
1178 m_paramCnt = 0;
1179
1180 returnErrIf(def==0, Err_MemoryAlloc);
1181 if(unlikely(error!=0)){
1182 delete def;
1183 setErrorCode(error);
1184 return NULL;
1185 }
1186
1187 if (doPrintQueryTree)
1188 {
1189 ndbout << "Query tree:" << endl;
1190 def->getQueryOperation(0U)
1191 .printTree(0, NdbQueryOperationDefImpl::SiblingMask());
1192 }
1193
1194 return def;
1195 }
1196
1197 inline int
takeOwnership(NdbQueryOperandImpl * operand)1198 NdbQueryBuilderImpl::takeOwnership(NdbQueryOperandImpl* operand)
1199 {
1200 if (unlikely(operand == NULL))
1201 {
1202 return Err_MemoryAlloc;
1203 }
1204 else if (unlikely(m_operands.push_back(operand) != 0))
1205 {
1206 assert(errno == ENOMEM);
1207 delete operand;
1208 return Err_MemoryAlloc;
1209 }
1210 return 0;
1211 }
1212
1213 inline int
takeOwnership(NdbQueryOperationDefImpl * operation)1214 NdbQueryBuilderImpl::takeOwnership(NdbQueryOperationDefImpl* operation)
1215 {
1216 if (unlikely(operation == NULL))
1217 {
1218 return Err_MemoryAlloc;
1219 }
1220 else if (unlikely(m_operations.push_back(operation) != 0))
1221 {
1222 assert(errno == ENOMEM);
1223 delete operation;
1224 return Err_MemoryAlloc;
1225 }
1226 return 0;
1227 }
1228
1229 NdbQueryOperand*
addOperand(NdbQueryOperandImpl * operand)1230 NdbQueryBuilderImpl::addOperand(NdbQueryOperandImpl* operand)
1231 {
1232 returnErrIf(takeOwnership(operand)!=0, Err_MemoryAlloc);
1233 return &operand->getInterface();
1234 }
1235
1236 ///////////////////////////////////
1237 // The (hidden) Impl of NdbQueryDef
1238 ///////////////////////////////////
1239 NdbQueryDefImpl::
NdbQueryDefImpl(const Vector<NdbQueryOperationDefImpl * > & operations,const Vector<NdbQueryOperandImpl * > & operands,int & error)1240 NdbQueryDefImpl(const Vector<NdbQueryOperationDefImpl*>& operations,
1241 const Vector<NdbQueryOperandImpl*>& operands,
1242 int& error)
1243 : m_interface(*this),
1244 m_operations(0),
1245 m_operands(0)
1246 {
1247 if (m_operations.assign(operations) || m_operands.assign(operands))
1248 {
1249 // Failed to allocate memory in Vector::assign().
1250 error = Err_MemoryAlloc;
1251 return;
1252 }
1253
1254 /* Grab first word, such that serialization of operation 0 will start from
1255 * offset 1, leaving space for the length field to be updated later
1256 */
1257 m_serializedDef.append(0);
1258 for(Uint32 i = 0; i<m_operations.size(); i++){
1259 NdbQueryOperationDefImpl* op = m_operations[i];
1260 error = op->serializeOperation(m_serializedDef);
1261 if(unlikely(error != 0)){
1262 return;
1263 }
1264 }
1265
1266 // Set length and number of nodes in tree.
1267 Uint32 cntLen;
1268 QueryTree::setCntLen(cntLen,
1269 m_operations[m_operations.size()-1]->getInternalOpNo()+1,
1270 m_serializedDef.getSize());
1271 m_serializedDef.put(0,cntLen);
1272
1273 #ifdef __TRACE_SERIALIZATION
1274 ndbout << "Serialized tree : ";
1275 for(Uint32 i = 0; i < m_serializedDef.getSize(); i++){
1276 char buf[12];
1277 sprintf(buf, "%.8x", m_serializedDef.get(i));
1278 ndbout << buf << " ";
1279 }
1280 ndbout << endl;
1281 #endif
1282 }
1283
~NdbQueryDefImpl()1284 NdbQueryDefImpl::~NdbQueryDefImpl()
1285 {
1286 // Release all NdbQueryOperations
1287 for (Uint32 i=0; i<m_operations.size(); ++i)
1288 {
1289 delete m_operations[i];
1290 }
1291 for (Uint32 i=0; i<m_operands.size(); ++i)
1292 {
1293 delete m_operands[i];
1294 }
1295 }
1296
1297 const NdbQueryOperationDefImpl*
getQueryOperation(const char * ident) const1298 NdbQueryDefImpl::getQueryOperation(const char* ident) const
1299 {
1300 if (ident==NULL)
1301 return NULL;
1302
1303 Uint32 sz = m_operations.size();
1304 const NdbQueryOperationDefImpl* const* opDefs = m_operations.getBase();
1305 for(Uint32 i = 0; i<sz; i++, opDefs++){
1306 const char* opName = (*opDefs)->getName();
1307 if(opName!=NULL && strcmp(opName, ident) == 0)
1308 return *opDefs;
1309 }
1310 return NULL;
1311 }
1312
1313 NdbQueryDef::QueryType
getQueryType() const1314 NdbQueryDefImpl::getQueryType() const
1315 {
1316 if (!m_operations[0]->isScanOperation())
1317 return NdbQueryDef::LookupQuery;
1318
1319 for (Uint32 i=1; i<m_operations.size(); ++i)
1320 {
1321 if (m_operations[i]->isScanOperation())
1322 return NdbQueryDef::MultiScanQuery;
1323 }
1324 return NdbQueryDef::SingleScanQuery;
1325 }
1326
1327 ////////////////////////////////////////////////////////////////
1328 // The (hidden) Impl of NdbQueryOperand (w/ various subclasses)
1329 ////////////////////////////////////////////////////////////////
1330
1331 /* Implicit typeconversion between related datatypes: */
convertUint8()1332 int NdbInt64ConstOperandImpl::convertUint8()
1333 {
1334 if (unlikely(m_value < 0 || m_value > 0xFF))
1335 return QRY_NUM_OPERAND_RANGE;
1336 m_converted.val.uint8 = (Uint8)m_value;
1337 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.uint8));
1338 return 0;
1339 }
convertInt8()1340 int NdbInt64ConstOperandImpl::convertInt8()
1341 {
1342 if (unlikely(m_value < -0x80L || m_value > 0x7F))
1343 return QRY_NUM_OPERAND_RANGE;
1344 m_converted.val.int8 = (Int8)m_value;
1345 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.int8));
1346 return 0;
1347 }
convertUint16()1348 int NdbInt64ConstOperandImpl::convertUint16()
1349 {
1350 if (unlikely(m_value < 0 || m_value > 0xFFFF))
1351 return QRY_NUM_OPERAND_RANGE;
1352 m_converted.val.uint16 = (Uint16)m_value;
1353 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.uint16));
1354 return 0;
1355 }
convertInt16()1356 int NdbInt64ConstOperandImpl::convertInt16()
1357 {
1358 if (unlikely(m_value < -0x8000L || m_value > 0x7FFF))
1359 return QRY_NUM_OPERAND_RANGE;
1360 m_converted.val.int16 = (Int16)m_value;
1361 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.int16));
1362 return 0;
1363 }
convertUint24()1364 int NdbInt64ConstOperandImpl::convertUint24()
1365 {
1366 if (unlikely(m_value < 0 || m_value > 0xFFFFFF))
1367 return QRY_NUM_OPERAND_RANGE;
1368 m_converted.val.uint32 = (Uint32)m_value;
1369 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.uint32));
1370 return 0;
1371 }
convertInt24()1372 int NdbInt64ConstOperandImpl::convertInt24()
1373 {
1374 if (unlikely(m_value < -0x800000L || m_value > 0x7FFFFF))
1375 return QRY_NUM_OPERAND_RANGE;
1376 m_converted.val.int32 = (Int32)m_value;
1377 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.int32));
1378 return 0;
1379 }
convertUint32()1380 int NdbInt64ConstOperandImpl::convertUint32()
1381 {
1382 if (unlikely(m_value < 0 || m_value > 0xFFFFFFFF))
1383 return QRY_NUM_OPERAND_RANGE;
1384 m_converted.val.uint32 = (Uint32)m_value;
1385 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.uint32));
1386 return 0;
1387 }
convertInt32()1388 int NdbInt64ConstOperandImpl::convertInt32()
1389 {
1390 if (unlikely(m_value < -((Int64)0x80000000L) || m_value > 0x7FFFFFFF))
1391 return QRY_NUM_OPERAND_RANGE;
1392 m_converted.val.int32 = (Int32)m_value;
1393 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.int32));
1394 return 0;
1395 }
convertInt64()1396 int NdbInt64ConstOperandImpl::convertInt64()
1397 {
1398 m_converted.val.int64 = m_value;
1399 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.int64));
1400 return 0;
1401 }
convertUint64()1402 int NdbInt64ConstOperandImpl::convertUint64()
1403 {
1404 m_converted.val.uint64 = (Uint64)m_value;
1405 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.uint64));
1406 return 0;
1407 }
1408
convertFloat()1409 int NdbDoubleConstOperandImpl::convertFloat()
1410 {
1411 m_converted.val.flt = (float)m_value;
1412 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.flt));
1413 return 0;
1414 }
convertDouble()1415 int NdbDoubleConstOperandImpl::convertDouble()
1416 {
1417 m_converted.val.dbl = m_value;
1418 m_converted.len = static_cast<Uint32>(sizeof(m_converted.val.dbl));
1419 return 0;
1420 }
1421
convertChar()1422 int NdbCharConstOperandImpl::convertChar()
1423 {
1424 Uint32 len = m_column->getLength();
1425 Uint32 srclen = (m_value) ? static_cast<Uint32>(strlen(m_value)) : 0;
1426 if (unlikely(srclen > len)) {
1427 // TODO: Truncates: May silently remove trailing spaces:
1428 return QRY_CHAR_OPERAND_TRUNCATED;
1429 srclen = len;
1430 }
1431
1432 char* dst = m_converted.getCharBuffer(len);
1433 if (unlikely(dst==NULL))
1434 return Err_MemoryAlloc;
1435
1436 memcpy (dst, m_value, srclen);
1437 if (unlikely(srclen < len)) {
1438 memset (dst+srclen, ' ', len-srclen);
1439 }
1440 return 0;
1441 } //NdbCharConstOperandImpl::convertChar
1442
1443
convertVChar()1444 int NdbCharConstOperandImpl::convertVChar()
1445 {
1446 Uint32 maxlen = m_column->getLength();
1447 Uint32 len = (m_value) ? static_cast<Uint32>(strlen(m_value)) : 0;
1448 if (unlikely(len > maxlen)) {
1449 // TODO: Truncates: May silently remove trailing spaces:
1450 return QRY_CHAR_OPERAND_TRUNCATED;
1451 len = maxlen;
1452 }
1453
1454 char* dst = m_converted.getCharBuffer(len);
1455 if (unlikely(dst==NULL))
1456 return Err_MemoryAlloc;
1457
1458 memcpy (dst, m_value, len);
1459 return 0;
1460 } //NdbCharConstOperandImpl::convertVChar
1461
1462
1463 /**
1464 * GenericConst is 'raw data' with minimal type checking and conversion capability.
1465 */
1466 int
convert2ColumnType()1467 NdbGenericConstOperandImpl::convert2ColumnType()
1468 {
1469 Uint32 len = m_len;
1470 Uint32 maxSize = m_column->getSizeInBytes();
1471
1472 char* dst = NULL;
1473
1474 if (likely(m_column->m_arrayType == NDB_ARRAYTYPE_FIXED))
1475 {
1476 if (unlikely(len != maxSize))
1477 return QRY_OPERAND_HAS_WRONG_TYPE;
1478
1479 dst = m_converted.getCharBuffer(len);
1480 if (unlikely(dst==NULL))
1481 return Err_MemoryAlloc;
1482 }
1483 else if (m_column->m_arrayType == NDB_ARRAYTYPE_SHORT_VAR)
1484 {
1485 if (unlikely(len+1 > maxSize))
1486 return QRY_CHAR_OPERAND_TRUNCATED;
1487
1488 dst = m_converted.getCharBuffer(len+1);
1489 if (unlikely(dst==NULL))
1490 return Err_MemoryAlloc;
1491
1492 *(Uint8*)dst++ = (Uint8)len;
1493 }
1494 else if (m_column->m_arrayType == NDB_ARRAYTYPE_MEDIUM_VAR)
1495 {
1496 if (unlikely(len+2 > maxSize))
1497 return QRY_CHAR_OPERAND_TRUNCATED;
1498
1499 dst = m_converted.getCharBuffer(len+2);
1500 if (unlikely(dst==NULL))
1501 return Err_MemoryAlloc;
1502
1503 *(Uint8*)dst++ = (Uint8)(len & 0xFF);
1504 *(Uint8*)dst++ = (Uint8)(len >> 8);
1505 }
1506 else
1507 {
1508 DBUG_ASSERT(0);
1509 }
1510
1511 memcpy (dst, m_value, len);
1512 return 0;
1513 } //NdbGenericConstOperandImpl::convert2ColumnType
1514
1515
1516 int
convert2ColumnType()1517 NdbConstOperandImpl::convert2ColumnType()
1518 {
1519 switch(m_column->getType()) {
1520 case NdbDictionary::Column::Tinyint: return convertInt8();
1521 case NdbDictionary::Column::Tinyunsigned: return convertUint8();
1522 case NdbDictionary::Column::Smallint: return convertInt16();
1523 case NdbDictionary::Column::Smallunsigned: return convertUint16();
1524 case NdbDictionary::Column::Mediumint: return convertInt24();
1525 case NdbDictionary::Column::Mediumunsigned: return convertUint24();
1526 case NdbDictionary::Column::Int: return convertInt32();
1527 case NdbDictionary::Column::Unsigned: return convertUint32();
1528 case NdbDictionary::Column::Bigint: return convertInt64();
1529 case NdbDictionary::Column::Bigunsigned: return convertUint64();
1530 case NdbDictionary::Column::Float: return convertFloat();
1531 case NdbDictionary::Column::Double: return convertDouble();
1532
1533 case NdbDictionary::Column::Decimal: return convertDec();
1534 case NdbDictionary::Column::Decimalunsigned: return convertUDec();
1535
1536 case NdbDictionary::Column::Char: return convertChar();
1537 case NdbDictionary::Column::Varchar: return convertVChar();
1538 case NdbDictionary::Column::Longvarchar: return convertLVChar();
1539 case NdbDictionary::Column::Binary: return convertBin();
1540 case NdbDictionary::Column::Varbinary: return convertVBin();
1541 case NdbDictionary::Column::Longvarbinary: return convertLVBin();
1542 case NdbDictionary::Column::Bit: return convertBit();
1543
1544 case NdbDictionary::Column::Date: return convertDate();
1545 case NdbDictionary::Column::Time: return convertTime();
1546 case NdbDictionary::Column::Datetime: return convertDatetime();
1547 case NdbDictionary::Column::Timestamp: return convertTimestamp();
1548 case NdbDictionary::Column::Year: return convertYear();
1549
1550 // Type conversion intentionally not supported (yet)
1551 case NdbDictionary::Column::Olddecimal:
1552 case NdbDictionary::Column::Olddecimalunsigned:
1553 case NdbDictionary::Column::Blob:
1554 case NdbDictionary::Column::Text:
1555 // Fall through:
1556
1557 default:
1558 case NdbDictionary::Column::Undefined: return QRY_OPERAND_HAS_WRONG_TYPE;
1559 }
1560
1561 return 0;
1562 } //NdbConstOperandImpl::convert2ColumnType
1563
1564
1565 int
bindOperand(const NdbColumnImpl & column,NdbQueryOperationDefImpl & operation)1566 NdbConstOperandImpl::bindOperand(
1567 const NdbColumnImpl& column,
1568 NdbQueryOperationDefImpl& operation)
1569 {
1570 const int error = NdbQueryOperandImpl::bindOperand(column,operation);
1571 if (unlikely(error))
1572 return error;
1573
1574 return convert2ColumnType();
1575 }
1576
1577
1578 int
bindOperand(const NdbColumnImpl & column,NdbQueryOperationDefImpl & operation)1579 NdbLinkedOperandImpl::bindOperand(
1580 const NdbColumnImpl& column,
1581 NdbQueryOperationDefImpl& operation)
1582 {
1583 const NdbColumnImpl& parentColumn = getParentColumn();
1584
1585 if (unlikely(column.m_type != parentColumn.m_type ||
1586 column.m_precision != parentColumn.m_precision ||
1587 column.m_scale != parentColumn.m_scale ||
1588 column.m_length != parentColumn.m_length ||
1589 column.m_cs != parentColumn.m_cs))
1590 return QRY_OPERAND_HAS_WRONG_TYPE; // Incompatible datatypes
1591
1592 if (unlikely(column.m_type == NdbDictionary::Column::Blob ||
1593 column.m_type == NdbDictionary::Column::Text))
1594 return QRY_OPERAND_HAS_WRONG_TYPE; // BLOB/CLOB datatypes intentionally not supported
1595
1596 // TODO: Allow and autoconvert compatible datatypes
1597
1598 // Register parent/child operation relations
1599 const int error = operation.linkWithParent(&this->m_parentOperation);
1600 if (unlikely(error))
1601 return error;
1602
1603 return NdbQueryOperandImpl::bindOperand(column,operation);
1604 }
1605
1606
1607 int
bindOperand(const NdbColumnImpl & column,NdbQueryOperationDefImpl & operation)1608 NdbParamOperandImpl::bindOperand(
1609 const NdbColumnImpl& column,
1610 NdbQueryOperationDefImpl& operation)
1611 {
1612 if (unlikely(column.m_type == NdbDictionary::Column::Blob ||
1613 column.m_type == NdbDictionary::Column::Text))
1614 return QRY_OPERAND_HAS_WRONG_TYPE; // BLOB/CLOB datatypes intentionally not supported
1615
1616 const int res = operation.addParamRef(this);
1617 if (unlikely(res != 0))
1618 {
1619 return res;
1620 }
1621 return NdbQueryOperandImpl::bindOperand(column,operation);
1622 }
1623
1624
1625 /////////////////////////////////////////////////////////////////
1626 // The (hidden) Impl of NdbQueryOperation (w/ various subclasses)
1627 ///////////////////////>/////////////////////////////////////////
1628
NdbQueryLookupOperationDefImpl(const NdbTableImpl & table,const NdbQueryOperand * const keys[],const NdbQueryOptionsImpl & options,const char * ident,Uint32 opNo,Uint32 internalOpNo,int & error)1629 NdbQueryLookupOperationDefImpl::NdbQueryLookupOperationDefImpl (
1630 const NdbTableImpl& table,
1631 const NdbQueryOperand* const keys[],
1632 const NdbQueryOptionsImpl& options,
1633 const char* ident,
1634 Uint32 opNo,
1635 Uint32 internalOpNo,
1636 int& error)
1637 : NdbQueryOperationDefImpl(table, options, ident, opNo,
1638 internalOpNo, error),
1639 m_interface(*this)
1640 {
1641 int i;
1642 for (i=0; i<MAX_ATTRIBUTES_IN_INDEX; ++i)
1643 { if (keys[i] == NULL)
1644 break;
1645 m_keys[i] = &keys[i]->getImpl();
1646 }
1647 assert (i > 0);
1648 assert (keys[i] == NULL);
1649 m_keys[i] = NULL;
1650 }
1651
NdbQueryIndexScanOperationDefImpl(const NdbIndexImpl & index,const NdbTableImpl & table,const NdbQueryIndexBound * bound,const NdbQueryOptionsImpl & options,const char * ident,Uint32 opNo,Uint32 internalOpNo,int & error)1652 NdbQueryIndexScanOperationDefImpl::NdbQueryIndexScanOperationDefImpl (
1653 const NdbIndexImpl& index,
1654 const NdbTableImpl& table,
1655 const NdbQueryIndexBound* bound,
1656 const NdbQueryOptionsImpl& options,
1657 const char* ident,
1658 Uint32 opNo,
1659 Uint32 internalOpNo,
1660 int& error)
1661 : NdbQueryScanOperationDefImpl(table, options, ident, opNo, internalOpNo,
1662 error),
1663 m_interface(*this),
1664 m_index(index),
1665 m_paramInPruneKey(false)
1666 {
1667 memset(&m_bound, 0, sizeof m_bound);
1668 if (bound!=NULL) {
1669
1670 if (bound->m_low!=NULL) {
1671 int i;
1672 for (i=0; bound->m_low[i] != NULL; ++i)
1673 { assert (i<MAX_ATTRIBUTES_IN_INDEX);
1674 m_bound.low[i] = &bound->m_low[i]->getImpl();
1675 }
1676 m_bound.lowKeys = i;
1677 } else {
1678 m_bound.lowKeys = 0;
1679 }
1680
1681 if (bound->m_high!=NULL) {
1682 int i;
1683 for (i=0; bound->m_high[i] != NULL; ++i)
1684 { assert (i<MAX_ATTRIBUTES_IN_INDEX);
1685 m_bound.high[i] = &bound->m_high[i]->getImpl();
1686 }
1687 m_bound.highKeys = i;
1688 } else {
1689 m_bound.highKeys = 0;
1690 }
1691
1692 m_bound.lowIncl = bound->m_lowInclusive;
1693 m_bound.highIncl = bound->m_highInclusive;
1694 }
1695 else {
1696 m_bound.lowKeys = m_bound.highKeys = 0;
1697 m_bound.lowIncl = m_bound.highIncl = true;
1698 }
1699 }
1700
1701 int
checkPrunable(const Uint32Buffer & keyInfo,Uint32 shortestBound,bool & isPruned,Uint32 & hashValue) const1702 NdbQueryIndexScanOperationDefImpl::checkPrunable(
1703 const Uint32Buffer& keyInfo,
1704 Uint32 shortestBound,
1705 bool& isPruned,
1706 Uint32& hashValue) const // 'hashValue' only defined if 'isPruned'
1707 {
1708 /**
1709 * Determine if scan may be pruned to a single partition:
1710 */
1711 isPruned = false;
1712 const NdbRecord* const tableRecord = getTable().getDefaultRecord();
1713 const NdbRecord* const indexRecord = m_index.getDefaultRecord();
1714 /**
1715 * This is the prefix (in number of fields) of the index key that will contain
1716 * all the distribution key fields.
1717 */
1718 const Uint32 prefixLength = indexRecord->m_min_distkey_prefix_length;
1719
1720 if (indexRecord->m_no_of_distribution_keys != tableRecord->m_no_of_distribution_keys)
1721 {
1722 return 0; // Index does not contain all fields in the distribution key.
1723 }
1724 else if (shortestBound < prefixLength)
1725 {
1726 // Bounds set on query instance are to short to contain full dist key.
1727 return 0;
1728 }
1729 // Bounds being part of query definitions should have been covered by 'shortestBound' above
1730 assert( (m_bound.lowKeys+m_bound.highKeys==0) ||
1731 (m_bound.lowKeys >= prefixLength && m_bound.highKeys >= prefixLength));
1732
1733 /**
1734 * The scan will be prunable if all upper and lower bound pairs are equal
1735 * for the prefix containing the distribution key, and if all bounds
1736 * give the same hash value for the distribution key.
1737 */
1738 Uint32 keyPos = 0;
1739
1740 // Loop over all bounds.
1741 Uint32 boundNo = 0;
1742 while (keyPos < keyInfo.getSize())
1743 {
1744 const Uint32 keyEnd = keyPos + (keyInfo.get(keyPos) >> 16);
1745 Ndb::Key_part_ptr distKey[NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY+1]
1746 = {{NULL, 0}};
1747
1748 // Loop over the fields in each bound.
1749 Uint32 keyPartNo = 0;
1750 Uint32 distKeyPartNo = 0;
1751 while (keyPos < keyEnd)
1752 {
1753 const NdbIndexScanOperation::BoundType type =
1754 static_cast<NdbIndexScanOperation::BoundType>
1755 (keyInfo.get(keyPos) & 0xF);
1756 const AttributeHeader attHead1(keyInfo.get(keyPos+1));
1757 const Ndb::Key_part_ptr keyPart1 = { keyInfo.addr(keyPos+2),
1758 attHead1.getByteSize() };
1759
1760 keyPos += 1+1+attHead1.getDataSize(); // Skip data read above.
1761
1762 const NdbColumnImpl& column
1763 = NdbColumnImpl::getImpl(*m_index.getColumn(keyPartNo));
1764
1765 switch (type)
1766 {
1767 case NdbIndexScanOperation::BoundEQ:
1768 break;
1769 case NdbIndexScanOperation::BoundGE:
1770 case NdbIndexScanOperation::BoundGT:
1771 /**
1772 * We have a one-sided limit for this field, which is part of
1773 * the prefix containing the distribution key. We thus cannot prune.
1774 */
1775 return 0;
1776 case NdbIndexScanOperation::BoundLE:
1777 case NdbIndexScanOperation::BoundLT:
1778 /**
1779 * If keyPart1 is a lower limit for this column, there may be an upper
1780 * limit also.
1781 */
1782 if (keyPos == keyEnd ||
1783 ((keyInfo.get(keyPos) & 0xF) != NdbIndexScanOperation::BoundGE &&
1784 (keyInfo.get(keyPos) & 0xF) != NdbIndexScanOperation::BoundGT))
1785 {
1786 /**
1787 * We have a one-sided limit for this field, which is part of
1788 * the prefix containing the distribution key. We thus cannot prune.
1789 */
1790 return 0;
1791 }
1792 else // There is an upper limit.
1793 {
1794 const AttributeHeader attHeadHigh(keyInfo.get(keyPos+1));
1795 const Ndb::Key_part_ptr highKeyPart = { keyInfo.addr(keyPos+2),
1796 attHeadHigh.getByteSize() };
1797
1798 keyPos += 1+1+attHeadHigh.getDataSize(); // Skip data read above.
1799
1800 /**
1801 * We must compare key parts in the prefix that contains the
1802 * distribution key. Even if subseqent parts should be different,
1803 * all matching tuples must have the same (distribution) hash.
1804 *
1805 * For example, assume there is a ordered index on {a, dist_key, b}.
1806 * Then any tuple in the range {a=c1, <dist key=c2>, b=c3} to
1807 * {a=c1, dist_key=c2, b=c4} will have dist_key=c2.
1808 * Then consider a range where fields before the distribution key are
1809 * different, e.g. {a=c6, <dist key=c7>, b=c8} to
1810 * {a=c9, <dist key=c7>, b=c8} then matching tuples can have any value
1811 * for the distribution key as long as c6 <= a <= c9, so there can be
1812 * no pruning.
1813 */
1814 assert(column.m_keyInfoPos < tableRecord->noOfColumns);
1815 const NdbRecord::Attr& recAttr = tableRecord->columns[column.m_keyInfoPos];
1816 /**
1817 * Shinked varchars should already have been converted in
1818 * NdbQueryImpl::setBound(), so no need to deal with them here.
1819 * (See also bug#56853 and http://lists.mysql.com/commits/121387 .)
1820 */
1821 assert((recAttr.flags & NdbRecord::IsMysqldShrinkVarchar) == 0);
1822 const int res=
1823 (*recAttr.compare_function)(recAttr.charset_info,
1824 keyPart1.ptr, keyPart1.len,
1825 highKeyPart.ptr, highKeyPart.len);
1826 if (res!=0)
1827 { // Not equal
1828 return 0;
1829 }
1830 } // if (keyPos == keyEnd ||
1831 break;
1832 default:
1833 assert(false);
1834 } // switch (type)
1835
1836 // If this field is part of the distribution key:
1837 // Keep the key value for later use by Ndb::computeHash.
1838 if (getTable().m_columns[column.m_keyInfoPos]->m_distributionKey)
1839 {
1840 /* Find the proper place for this field in the distribution key.*/
1841 Ndb::Key_part_ptr* distKeyPtr = distKey;
1842 for (Uint32 i = 0; i < column.m_keyInfoPos; i++)
1843 {
1844 if (getTable().m_columns[i]->m_distributionKey)
1845 {
1846 distKeyPtr++;
1847 }
1848 }
1849
1850 assert(distKeyPtr->len == 0 && distKeyPtr->ptr == NULL);
1851 *distKeyPtr = keyPart1;
1852 distKeyPartNo++;
1853 }
1854
1855 keyPartNo++;
1856 if (keyPartNo == prefixLength)
1857 {
1858 /**
1859 * Skip key parts after the prefix containing the distribution key,
1860 * as these do not affect prunability.
1861 */
1862 keyPos = keyEnd;
1863 }
1864 } // while (keyPos < keyEnd)
1865
1866 assert(distKeyPartNo == tableRecord->m_no_of_distribution_keys);
1867
1868 // hi/low are equal and prunable bounds.
1869 Uint32 newHashValue = 0;
1870 const int error = Ndb::computeHash(&newHashValue, &getTable(), distKey,
1871 NULL, 0);
1872 if (unlikely(error))
1873 return error;
1874
1875 if (boundNo == 0)
1876 {
1877 hashValue = newHashValue;
1878 }
1879 else if (hashValue != newHashValue)
1880 {
1881 /* This bound does not have the same hash value as the previous one.
1882 * So we make the pessimistic assumtion that it will not hash to the
1883 * same node. (See also comments in
1884 * NdbScanOperation::getPartValueFromInfo()).
1885 */
1886 return 0;
1887 }
1888
1889 boundNo++;
1890 } // while (keyPos < keyInfo.getSize())
1891
1892 isPruned = true;
1893 return 0;
1894 } // NdbQueryIndexScanOperationDefImpl::checkPrunable
1895
1896
NdbQueryOperationDefImpl(const NdbTableImpl & table,const NdbQueryOptionsImpl & options,const char * ident,Uint32 opNo,Uint32 internalOpNo,int & error)1897 NdbQueryOperationDefImpl::NdbQueryOperationDefImpl (
1898 const NdbTableImpl& table,
1899 const NdbQueryOptionsImpl& options,
1900 const char* ident,
1901 Uint32 opNo,
1902 Uint32 internalOpNo,
1903 int& error)
1904 :m_isPrepared(false),
1905 m_diskInChildProjection(false),
1906 m_table(table),
1907 m_ident(ident),
1908 m_opNo(opNo), m_internalOpNo(internalOpNo),
1909 m_options(options),
1910 m_parent(NULL),
1911 m_children(0),
1912 m_params(0),
1913 m_spjProjection(0)
1914 {
1915 if (unlikely(m_internalOpNo >= NDB_SPJ_MAX_TREE_NODES))
1916 {
1917 error = QRY_DEFINITION_TOO_LARGE;
1918 return;
1919 }
1920 if (m_options.m_parent != NULL)
1921 {
1922 m_parent = m_options.m_parent;
1923 const int res = m_parent->addChild(this);
1924 if (unlikely(res != 0))
1925 {
1926 error = res;
1927 return;
1928 }
1929 } // else, ::linkWithParent() will assign 'm_parent'
1930 }
1931
1932
1933 int
addChild(NdbQueryOperationDefImpl * childOp)1934 NdbQueryOperationDefImpl::addChild(NdbQueryOperationDefImpl* childOp)
1935 {
1936 for (Uint32 i=0; i<m_children.size(); ++i)
1937 { if (m_children[i] == childOp)
1938 return 0;
1939 }
1940 if (likely(m_children.push_back(childOp) == 0))
1941 {
1942 return 0;
1943 }
1944 else
1945 {
1946 assert(errno == ENOMEM);
1947 return Err_MemoryAlloc;
1948 }
1949 }
1950
1951 void
removeChild(const NdbQueryOperationDefImpl * childOp)1952 NdbQueryOperationDefImpl::removeChild(const NdbQueryOperationDefImpl* childOp)
1953 {
1954 for (unsigned i=0; i<m_children.size(); ++i)
1955 {
1956 if (m_children[i] == childOp)
1957 {
1958 m_children.erase(i);
1959 return;
1960 }
1961 }
1962 }
1963
1964 bool
isChildOf(const NdbQueryOperationDefImpl * parentOp) const1965 NdbQueryOperationDefImpl::isChildOf(const NdbQueryOperationDefImpl* parentOp) const
1966 {
1967 if (m_parent != NULL)
1968 { if (this->m_parent == parentOp)
1969 {
1970 #ifndef NDEBUG
1971 // Assert that parentOp also refer 'this' as a child.
1972 for (Uint32 j=0; j<parentOp->getNoOfChildOperations(); j++)
1973 { if (&parentOp->getChildOperation(j) == this)
1974 return true;
1975 }
1976 assert(false);
1977 #endif
1978 return true;
1979 }
1980 else if (m_parent->isChildOf(parentOp))
1981 {
1982 return true;
1983 }
1984 }
1985 return false;
1986 }
1987
1988 int
linkWithParent(NdbQueryOperationDefImpl * parentOp)1989 NdbQueryOperationDefImpl::linkWithParent(NdbQueryOperationDefImpl* parentOp)
1990 {
1991 if (this->isChildOf(parentOp))
1992 {
1993 // There should only be a single parent/child relationship registered.
1994 return 0;
1995 }
1996
1997 if (m_parent != NULL)
1998 {
1999 /**
2000 * Multiple parental relationship not allowed.
2001 * It is likely that the conflict is due to one of the
2002 * parents actually being a grand parent.
2003 * This can be resolved if existing parent actually was a grandparent.
2004 * Then register new parentOp as the real parrent.
2005 */
2006 if (parentOp->isChildOf(m_parent))
2007 { // Remove existing grandparent linkage being replaced by parentOp.
2008 m_parent->removeChild(this);
2009 m_parent = NULL;
2010 }
2011 else
2012 { // This is a real multiparent error.
2013 return QRY_MULTIPLE_PARENTS;
2014 }
2015 }
2016 m_parent = parentOp;
2017 parentOp->addChild(this);
2018 return 0;
2019 }
2020
2021
2022 // Register a linked reference to a column available from this operation
2023 Uint32
addColumnRef(const NdbColumnImpl * column,int & error)2024 NdbQueryOperationDefImpl::addColumnRef(const NdbColumnImpl* column,
2025 int& error)
2026 {
2027 Uint32 spjRef;
2028 for (spjRef=0; spjRef<m_spjProjection.size(); ++spjRef)
2029 { if (m_spjProjection[spjRef] == column)
2030 return spjRef;
2031 }
2032
2033 // Add column if not already available
2034 if (unlikely(m_spjProjection.push_back(column) != 0))
2035 {
2036 assert(errno == ENOMEM);
2037 error = Err_MemoryAlloc;
2038 return ~0;
2039 }
2040 if (column->getStorageType() == NDB_STORAGETYPE_DISK)
2041 {
2042 m_diskInChildProjection = true;
2043 }
2044 return spjRef;
2045 }
2046
addParamRef(const NdbParamOperandImpl * param)2047 int NdbQueryOperationDefImpl::addParamRef(const NdbParamOperandImpl* param)
2048 {
2049 if (unlikely(m_params.push_back(param) != 0))
2050 {
2051 assert(errno == ENOMEM);
2052 return Err_MemoryAlloc;
2053 }
2054 return 0;
2055 }
2056
2057 /** This class is used for serializing sequences of 16 bit integers,
2058 * where the first 16 bit integer specifies the length of the sequence.
2059 */
2060 class Uint16Sequence{
2061 public:
Uint16Sequence(Uint32Buffer & buffer,Uint32 size)2062 explicit Uint16Sequence(Uint32Buffer& buffer, Uint32 size):
2063 m_seq(NULL),
2064 m_size(size),
2065 m_pos(0),
2066 m_finished(false)
2067 {
2068 m_seq = buffer.alloc(1 + size/2);
2069 assert (size <= 0xFFFF);
2070 m_seq[0] = size;
2071 }
2072
~Uint16Sequence()2073 ~Uint16Sequence()
2074 { assert(m_finished);
2075 }
2076
2077 /** Add an item to the sequence.*/
append(Uint16 value)2078 void append(Uint16 value) {
2079 assert(m_pos < m_size);
2080 assert(m_seq);
2081 m_pos++;
2082 if ((m_pos & 1) == 1) {
2083 m_seq[m_pos/2] |= (value<<16);
2084 } else {
2085 m_seq[m_pos/2] = value;
2086 }
2087 }
2088
2089
2090 /** End the sequence and pad possibly unused Int16 word at end. */
finish()2091 void finish() {
2092 assert(m_pos == m_size);
2093 assert(!m_finished);
2094 m_finished = true;
2095 if (m_pos>0) {
2096 if ((m_pos & 1) == 0) {
2097 m_seq[m_pos/2] |= (0xBABE<<16);
2098 }
2099 }
2100 }
2101
2102 private:
2103 /** Should not be copied.*/
2104 Uint16Sequence(Uint16Sequence&);
2105 /** Should not be assigned.*/
2106 Uint16Sequence& operator=(Uint16Sequence&);
2107
2108 Uint32* m_seq; // Preallocated buffer to append Uint16's into
2109 const Uint32 m_size; // Uint16 words available in m_seq
2110 Uint32 m_pos; // Current Uint16 word to fill in
2111 bool m_finished; // Debug assert of correct call convention
2112 };
2113
2114
2115 Uint32
appendParentList(Uint32Buffer & serializedDef) const2116 NdbQueryOperationDefImpl::appendParentList(Uint32Buffer& serializedDef) const
2117 {
2118 if (getParentOperation() != NULL)
2119 {
2120 Uint16Sequence parentSeq(serializedDef, 1);
2121 assert (getParentOperation()->getInternalOpNo() < getInternalOpNo());
2122 parentSeq.append(getParentOperation()->getInternalOpNo());
2123 parentSeq.finish();
2124 return DABits::NI_HAS_PARENT;
2125 }
2126 return 0;
2127 } // NdbQueryOperationDefImpl::appendParentList
2128
2129
2130 /* Add the projection that should be send to the SPJ block such that
2131 * child operations can be instantiated.
2132 */
2133 Uint32
appendChildProjection(Uint32Buffer & serializedDef) const2134 NdbQueryOperationDefImpl::appendChildProjection(Uint32Buffer& serializedDef) const
2135 {
2136 Uint32 requestInfo = 0;
2137 if (m_spjProjection.size() > 0 || getNoOfChildOperations() > 0)
2138 {
2139 requestInfo |= DABits::NI_LINKED_ATTR;
2140 Uint16Sequence spjProjSeq(serializedDef, m_spjProjection.size());
2141 for (Uint32 i = 0; i<m_spjProjection.size(); i++)
2142 {
2143 spjProjSeq.append(m_spjProjection[i]->getColumnNo());
2144 }
2145 spjProjSeq.finish();
2146
2147 if (m_diskInChildProjection)
2148 {
2149 requestInfo |= DABits::NI_LINKED_DISK;
2150 }
2151 }
2152 return requestInfo;
2153 } // NdbQueryOperationDefImpl::appendChildProjection
2154
2155 /** Used by NdbQueryOperationDefImpl::printTree() to print the arrows
2156 * that connect the tree nodes.
2157 */
printMargin(Uint32 depth,NdbQueryOperationDefImpl::SiblingMask hasMoreSiblingsMask,bool header)2158 static void printMargin(Uint32 depth,
2159 NdbQueryOperationDefImpl::SiblingMask
2160 hasMoreSiblingsMask,
2161 bool header)
2162 {
2163 if (depth > 0)
2164 {
2165 // Print vertical lines to the siblings of the ancestore nodes.
2166 for (Uint32 i = 0; i<depth-1; i++)
2167 {
2168 if (hasMoreSiblingsMask.get(i+1))
2169 {
2170 ndbout << "| ";
2171 }
2172 else
2173 {
2174 ndbout << " ";
2175 }
2176 }
2177 if (header)
2178 {
2179 ndbout << "+->";
2180 }
2181 else if (hasMoreSiblingsMask.get(depth))
2182 {
2183 ndbout << "| ";
2184 }
2185 else
2186 {
2187 ndbout << " ";
2188 }
2189 }
2190 }
2191
2192 void
printTree(Uint32 depth,SiblingMask hasMoreSiblingsMask) const2193 NdbQueryOperationDefImpl::printTree(Uint32 depth,
2194 SiblingMask hasMoreSiblingsMask) const
2195 {
2196 // Print vertical line leading down to this node.
2197 SiblingMask firstLineMask = hasMoreSiblingsMask;
2198 firstLineMask.set(depth);
2199 printMargin(depth, firstLineMask, false);
2200 ndbout << endl;
2201 // Print +-> leading to this node.
2202 printMargin(depth, hasMoreSiblingsMask, true);
2203 ndbout << NdbQueryOperationDef::getTypeName(getType()) << endl;
2204 printMargin(depth, hasMoreSiblingsMask, false);
2205 // Print attributes.
2206 ndbout << " opNo: " << getOpNo()
2207 << " (internal: " << getInternalOpNo() << ")" << endl;
2208 printMargin(depth, hasMoreSiblingsMask, false);
2209 ndbout << " table: " << getTable().getName() << endl;
2210 if (getIndex() != NULL)
2211 {
2212 printMargin(depth, hasMoreSiblingsMask, false);
2213 ndbout << " index: " << getIndex()->getName() << endl;
2214 }
2215
2216 for (int childNo = 0;
2217 childNo < static_cast<int>(getNoOfChildOperations());
2218 childNo++)
2219 {
2220 if (childNo == 0)
2221 {
2222 /* For each child but the last one, use a mask with an extra bit set to
2223 * indicate that there are more siblings.
2224 */
2225 hasMoreSiblingsMask.set(depth+1);
2226 }
2227 if (childNo == static_cast<int>(getNoOfChildOperations()) - 1)
2228 {
2229 // The last child has no more siblings.
2230 hasMoreSiblingsMask.clear(depth+1);
2231 }
2232 getChildOperation(childNo).printTree(depth+1, hasMoreSiblingsMask);
2233 }
2234 } // NdbQueryOperationDefImpl::printTree()
2235
2236
2237 Uint32
appendKeyPattern(Uint32Buffer & serializedDef) const2238 NdbQueryLookupOperationDefImpl::appendKeyPattern(Uint32Buffer& serializedDef) const
2239 {
2240 Uint32 appendedPattern = 0;
2241
2242 /**
2243 * Key value for root operation is constructed when query is instantiated with
2244 * NdbQueryOperationImpl::prepareIndexKeyInfo()
2245 */
2246 if (getOpNo() == 0)
2247 return 0;
2248
2249 if (m_keys[0]!=NULL)
2250 {
2251 Uint32 startPos = serializedDef.getSize();
2252 serializedDef.append(0); // Grab first word for length field, updated at end
2253 int paramCnt = 0;
2254 int keyNo = 0;
2255 const NdbQueryOperandImpl* key = m_keys[0];
2256 do
2257 {
2258 switch(key->getKind()){
2259 case NdbQueryOperandImpl::Linked:
2260 {
2261 appendedPattern |= DABits::NI_KEY_LINKED;
2262 const NdbLinkedOperandImpl& linkedOp = *static_cast<const NdbLinkedOperandImpl*>(key);
2263 const NdbQueryOperationDefImpl* parent = getParentOperation();
2264 uint32 levels = 0;
2265 while (parent != &linkedOp.getParentOperation())
2266 {
2267 if (parent->getType() == NdbQueryOperationDef::UniqueIndexAccess) // Represented with two nodes in QueryTree
2268 levels+=2;
2269 else
2270 levels+=1;
2271 parent = parent->getParentOperation();
2272 assert(parent != NULL);
2273 }
2274 if (levels > 0)
2275 {
2276 serializedDef.append(QueryPattern::parent(levels));
2277 }
2278 serializedDef.append(QueryPattern::col(linkedOp.getLinkedColumnIx()));
2279 break;
2280 }
2281 case NdbQueryOperandImpl::Const:
2282 {
2283 appendedPattern |= DABits::NI_KEY_CONSTS;
2284 const NdbConstOperandImpl& constOp = *static_cast<const NdbConstOperandImpl*>(key);
2285
2286 // No of words needed for storing the constant data.
2287 const Uint32 wordCount = AttributeHeader::getDataSize(constOp.getSizeInBytes());
2288 // Set type and length in words of key pattern field.
2289 serializedDef.append(QueryPattern::data(wordCount));
2290 serializedDef.appendBytes(constOp.getAddr(),constOp.getSizeInBytes());
2291 break;
2292 }
2293 case NdbQueryOperandImpl::Param:
2294 {
2295 appendedPattern |= DABits::NI_KEY_PARAMS;
2296 serializedDef.append(QueryPattern::param(paramCnt++));
2297 break;
2298 }
2299 default:
2300 assert(false);
2301 }
2302 key = m_keys[++keyNo];
2303 } while (key!=NULL);
2304
2305 // Set total length of key pattern.
2306 Uint32 len = serializedDef.getSize() - startPos -1;
2307 serializedDef.put(startPos, (paramCnt << 16) | (len));
2308 }
2309
2310 return appendedPattern;
2311 } // NdbQueryLookupOperationDefImpl::appendKeyPattern
2312
2313
2314 Uint32
appendPrunePattern(Uint32Buffer & serializedDef)2315 NdbQueryIndexScanOperationDefImpl::appendPrunePattern(Uint32Buffer& serializedDef)
2316 {
2317 Uint32 appendedPattern = 0;
2318
2319 /**
2320 * Bound value for root operation is constructed when query is instantiated with
2321 * NdbQueryOperationImpl::prepareIndexKeyInfo()
2322 */
2323 if (getOpNo() == 0)
2324 return 0;
2325
2326 if (m_bound.lowKeys>0 || m_bound.highKeys>0)
2327 {
2328 const NdbRecord* const tableRecord = getTable().getDefaultRecord();
2329 const NdbRecord* const indexRecord = m_index.getDefaultRecord();
2330
2331 if (indexRecord->m_no_of_distribution_keys != tableRecord->m_no_of_distribution_keys)
2332 {
2333 return 0; // Index does not contain all fields in the distribution key.
2334 }
2335
2336 /**
2337 * This is the prefix (in number of fields) of the index key that will contain
2338 * all the distribution key fields.
2339 */
2340 Uint32 distKeys = indexRecord->m_min_distkey_prefix_length;
2341 if (m_bound.lowKeys < distKeys || m_bound.highKeys < distKeys)
2342 {
2343 // Bounds set on query definition are to short to contain full dist key.
2344 return 0;
2345 }
2346
2347 /* All low/high bounds should be defined equal within the 'distKey' */
2348 for (unsigned keyNo = 0; keyNo < distKeys; keyNo++)
2349 {
2350 if (m_bound.low[keyNo] != m_bound.high[keyNo])
2351 return 0;
2352 }
2353
2354 {
2355 int paramCnt = 0;
2356 Uint32 startPos = serializedDef.getSize();
2357 serializedDef.append(0); // Grab first word for length field, updated at end
2358
2359 for (unsigned i = 0; i < indexRecord->distkey_index_length; i++)
2360 {
2361 const unsigned keyNo = indexRecord->distkey_indexes[i];
2362 assert(keyNo<indexRecord->noOfColumns);
2363 const NdbRecord::Attr& indexAttr = indexRecord->columns[keyNo];
2364 assert(indexAttr.flags & NdbRecord::IsDistributionKey);
2365 assert(indexAttr.index_attrId<m_bound.lowKeys);
2366 const NdbQueryOperandImpl* key = m_bound.low[indexAttr.index_attrId];
2367
2368 switch(key->getKind())
2369 {
2370 case NdbQueryOperandImpl::Linked:
2371 {
2372 appendedPattern |= QN_ScanIndexNode::SI_PRUNE_LINKED;
2373 const NdbLinkedOperandImpl& linkedOp = *static_cast<const NdbLinkedOperandImpl*>(key);
2374 const NdbQueryOperationDefImpl* parent = getParentOperation();
2375 uint32 levels = 0;
2376 while (parent != &linkedOp.getParentOperation())
2377 {
2378 if (parent->getType() == NdbQueryOperationDef::UniqueIndexAccess) // Represented with two nodes in QueryTree
2379 levels+=2;
2380 else
2381 levels+=1;
2382 parent = parent->getParentOperation();
2383 assert(parent != NULL);
2384 }
2385 if (levels > 0)
2386 {
2387 serializedDef.append(QueryPattern::parent(levels));
2388 }
2389 serializedDef.append(QueryPattern::col(linkedOp.getLinkedColumnIx()));
2390 break;
2391 }
2392 case NdbQueryOperandImpl::Const:
2393 {
2394 // appendedPattern |= QN_ScanIndexNode::SI_PRUNE_CONST;
2395 const NdbConstOperandImpl& constOp = *static_cast<const NdbConstOperandImpl*>(key);
2396
2397 // No of words needed for storing the constant data.
2398 const Uint32 wordCount = AttributeHeader::getDataSize(constOp.getSizeInBytes());
2399 // Set type and length in words of key pattern field.
2400 serializedDef.append(QueryPattern::data(wordCount));
2401 serializedDef.appendBytes(constOp.getAddr(),
2402 constOp.getSizeInBytes());
2403 break;
2404 }
2405 case NdbQueryOperandImpl::Param:
2406 appendedPattern |= QN_ScanIndexNode::SI_PRUNE_PARAMS;
2407 m_paramInPruneKey = true;
2408 serializedDef.append(QueryPattern::param(paramCnt++));
2409 break;
2410 default:
2411 assert(false);
2412 }
2413 }
2414
2415 // Set total length of bound pattern.
2416 Uint32 len = serializedDef.getSize() - startPos -1;
2417 serializedDef.put(startPos, (paramCnt << 16) | (len));
2418 appendedPattern |= QN_ScanIndexNode::SI_PRUNE_PATTERN;
2419 }
2420 }
2421 return appendedPattern;
2422 } // NdbQueryIndexScanOperationDefImpl::appendPrunePattern
2423
2424
2425 Uint32
appendBoundValue(Uint32Buffer & serializedDef,NdbIndexScanOperation::BoundType type,const NdbQueryOperandImpl * value,int & paramCnt) const2426 NdbQueryIndexScanOperationDefImpl::appendBoundValue(
2427 Uint32Buffer& serializedDef,
2428 NdbIndexScanOperation::BoundType type,
2429 const NdbQueryOperandImpl* value,
2430 int& paramCnt) const
2431 {
2432 Uint32 appendedPattern = 0;
2433
2434 // Append BoundType as a constant value
2435 serializedDef.append(QueryPattern::data(1));
2436 serializedDef.append(type);
2437
2438 switch(value->getKind())
2439 {
2440 case NdbQueryOperandImpl::Linked:
2441 {
2442 appendedPattern |= DABits::NI_KEY_LINKED;
2443 const NdbLinkedOperandImpl& linkedOp = *static_cast<const NdbLinkedOperandImpl*>(value);
2444 const NdbQueryOperationDefImpl* parent = getParentOperation();
2445 uint32 levels = 0;
2446 while (parent != &linkedOp.getParentOperation())
2447 {
2448 if (parent->getType() == NdbQueryOperationDef::UniqueIndexAccess) // Represented with two nodes in QueryTree
2449 levels+=2;
2450 else
2451 levels+=1;
2452 parent = parent->getParentOperation();
2453 assert(parent != NULL);
2454 }
2455 if (levels > 0)
2456 {
2457 serializedDef.append(QueryPattern::parent(levels));
2458 }
2459 // serializedDef.append(QueryPattern::col(linkedOp.getLinkedColumnIx()));
2460 serializedDef.append(QueryPattern::attrInfo(linkedOp.getLinkedColumnIx())); // col w/ AttributeHeader
2461 break;
2462 }
2463 case NdbQueryOperandImpl::Const:
2464 {
2465 appendedPattern |= DABits::NI_KEY_CONSTS;
2466 const NdbConstOperandImpl& constOp = *static_cast<const NdbConstOperandImpl*>(value);
2467
2468 // Build the AttributeHeader for const value
2469 // (AttributeId is later filled in by SPJ in Dbspj::scanIndex_fixupBound())
2470 AttributeHeader ah(0, constOp.getSizeInBytes());
2471
2472 // Constant is then appended as AttributeHeader + const-value
2473 serializedDef.append(QueryPattern::data(1+ah.getDataSize()));
2474 serializedDef.append(ah.m_value);
2475 serializedDef.appendBytes(constOp.getAddr(),constOp.getSizeInBytes());
2476 break;
2477 }
2478 case NdbQueryOperandImpl::Param:
2479 {
2480 appendedPattern |= DABits::NI_KEY_PARAMS;
2481 // serializedDef.append(QueryPattern::param(paramCnt++));
2482 serializedDef.append(QueryPattern::paramHeader(paramCnt++));
2483 break;
2484 }
2485 default:
2486 assert(false);
2487 }
2488
2489 return appendedPattern;
2490 } // NdbQueryIndexScanOperationDefImpl::appendBoundValue
2491
2492
2493 /**
2494 * Append the complete patterns for hi & low bound for an index range scan.
2495 * Each bound may consist of multiple values which in turn are
2496 * added with NdbQueryIndexScanOperationDefImpl::appendBoundPattern()
2497 */
2498 Uint32
appendBoundPattern(Uint32Buffer & serializedDef) const2499 NdbQueryIndexScanOperationDefImpl::appendBoundPattern(Uint32Buffer& serializedDef) const
2500 {
2501 Uint32 appendedPattern = 0;
2502
2503 /**
2504 * Bound value for root operation is constructed when query is instantiated with
2505 * NdbQueryOperationImpl::prepareIndexKeyInfo()
2506 */
2507 if (getOpNo() == 0)
2508 return 0;
2509
2510 if (m_bound.lowKeys>0 || m_bound.highKeys>0)
2511 {
2512 int paramCnt = 0;
2513 Uint32 startPos = serializedDef.getSize();
2514 serializedDef.append(0); // Grab first word for length field, updated at end
2515
2516 const uint key_count =
2517 (m_bound.lowKeys >= m_bound.highKeys) ? m_bound.lowKeys : m_bound.highKeys;
2518
2519 for (uint keyNo=0; keyNo<key_count; ++keyNo)
2520 {
2521 NdbIndexScanOperation::BoundType bound_type;
2522
2523 /* If upper and lower limits are equal, a single BoundEQ is sufficient */
2524 if (keyNo < m_bound.lowKeys &&
2525 keyNo < m_bound.highKeys &&
2526 m_bound.low[keyNo] == m_bound.high[keyNo])
2527 {
2528 /* Inclusive if defined, or matching rows can include this value */
2529 bound_type= NdbIndexScanOperation::BoundEQ;
2530
2531 appendedPattern |=
2532 appendBoundValue(serializedDef, bound_type, m_bound.low[keyNo], paramCnt);
2533
2534 } else {
2535
2536 /* If key is part of lower bound */
2537 if (keyNo < m_bound.lowKeys)
2538 {
2539 /* Inclusive if defined, or matching rows can include this value */
2540 bound_type= m_bound.lowIncl || keyNo+1 < m_bound.lowKeys ?
2541 NdbIndexScanOperation::BoundLE : NdbIndexScanOperation::BoundLT;
2542
2543 appendedPattern |=
2544 appendBoundValue(serializedDef, bound_type, m_bound.low[keyNo], paramCnt);
2545 }
2546
2547 /* If key is part of upper bound */
2548 if (keyNo < m_bound.highKeys)
2549 {
2550 /* Inclusive if defined, or matching rows can include this value */
2551 bound_type= m_bound.highIncl || keyNo+1 < m_bound.highKeys ?
2552 NdbIndexScanOperation::BoundGE : NdbIndexScanOperation::BoundGT;
2553
2554 appendedPattern |=
2555 appendBoundValue(serializedDef, bound_type, m_bound.high[keyNo], paramCnt);
2556 }
2557 }
2558 } // for 'all bound values'
2559
2560 // Set total length of bound pattern.
2561 Uint32 len = serializedDef.getSize() - startPos -1;
2562 serializedDef.put(startPos, (paramCnt << 16) | (len));
2563 }
2564
2565 return appendedPattern;
2566 } // NdbQueryIndexScanOperationDefImpl::appendBoundPattern
2567
2568
2569 int
2570 NdbQueryPKLookupOperationDefImpl
serializeOperation(Uint32Buffer & serializedDef)2571 ::serializeOperation(Uint32Buffer& serializedDef)
2572 {
2573 assert (m_keys[0]!=NULL);
2574 // This method should only be invoked once.
2575 assert (!m_isPrepared);
2576 m_isPrepared = true;
2577
2578 // Reserve memory for LookupNode, fill in contents later when
2579 // 'length' and 'requestInfo' has been calculated.
2580 Uint32 startPos = serializedDef.getSize();
2581 serializedDef.alloc(QN_LookupNode::NodeSize);
2582 Uint32 requestInfo = 0;
2583
2584 /**
2585 * NOTE: Order of sections within the optional part is fixed as:
2586 * Part1: 'NI_HAS_PARENT'
2587 * Part2: 'NI_KEY_PARAMS, NI_KEY_LINKED, NI_KEY_CONST'
2588 * PART3: 'NI_LINKED_ATTR ++
2589 */
2590
2591 // Optional part1: Make list of parent nodes.
2592 requestInfo |= appendParentList (serializedDef);
2593
2594 // Part2: Append m_keys[] values specifying lookup key.
2595 requestInfo |= appendKeyPattern(serializedDef);
2596
2597 // Part3: Columns required by SPJ to instantiate further child operations.
2598 requestInfo |= appendChildProjection(serializedDef);
2599
2600 // Fill in LookupNode contents (Already allocated, 'startPos' is our handle:
2601 QN_LookupNode* node = reinterpret_cast<QN_LookupNode*>(serializedDef.addr(startPos));
2602 if (unlikely(node==NULL)) {
2603 return Err_MemoryAlloc;
2604 }
2605 node->tableId = getTable().getObjectId();
2606 node->tableVersion = getTable().getObjectVersion();
2607 node->requestInfo = requestInfo;
2608 const Uint32 length = serializedDef.getSize() - startPos;
2609 if (unlikely(length > 0xFFFF)) {
2610 return QRY_DEFINITION_TOO_LARGE; //Query definition too large.
2611 } else {
2612 QueryNode::setOpLen(node->len, QueryNode::QN_LOOKUP, length);
2613 }
2614
2615 #ifdef __TRACE_SERIALIZATION
2616 ndbout << "Serialized node " << getInternalOpNo() << " : ";
2617 for (Uint32 i = startPos; i < serializedDef.getSize(); i++) {
2618 char buf[12];
2619 sprintf(buf, "%.8x", serializedDef.get(i));
2620 ndbout << buf << " ";
2621 }
2622 ndbout << endl;
2623 #endif
2624
2625 return 0;
2626 } // NdbQueryPKLookupOperationDefImpl::serializeOperation
2627
2628
2629 int
2630 NdbQueryIndexOperationDefImpl
serializeOperation(Uint32Buffer & serializedDef)2631 ::serializeOperation(Uint32Buffer& serializedDef)
2632 {
2633 assert (m_keys[0]!=NULL);
2634 // This method should only be invoked once.
2635 assert (!m_isPrepared);
2636 m_isPrepared = true;
2637
2638 /**
2639 * Serialize unique index as a seperate lookupNode
2640 */
2641 {
2642 // Reserve memory for Index LookupNode, fill in contents later when
2643 // 'length' and 'requestInfo' has been calculated.
2644 Uint32 startPos = serializedDef.getSize();
2645 serializedDef.alloc(QN_LookupNode::NodeSize);
2646 Uint32 requestInfo = QN_LookupNode::L_UNIQUE_INDEX;
2647
2648 // Optional part1: Make list of parent nodes.
2649 assert (getInternalOpNo() > 0);
2650 requestInfo |= appendParentList (serializedDef);
2651
2652 // Part2: m_keys[] are the keys to be used for index
2653 requestInfo |= appendKeyPattern(serializedDef);
2654
2655 /* Basetable is executed as child operation of index:
2656 * Add projection of (only) NDB$PK column which is hidden *after* last index column.
2657 */
2658 {
2659 requestInfo |= DABits::NI_LINKED_ATTR;
2660 Uint16Sequence spjProjSeq(serializedDef,1);
2661 spjProjSeq.append(getIndex()->getNoOfColumns());
2662 spjProjSeq.finish();
2663 }
2664
2665 // Fill in LookupNode contents (Already allocated, 'startPos' is our handle:
2666 QN_LookupNode* node = reinterpret_cast<QN_LookupNode*>(serializedDef.addr(startPos));
2667 if (unlikely(node==NULL)) {
2668 return Err_MemoryAlloc;
2669 }
2670 node->tableId = getIndex()->getObjectId();
2671 node->tableVersion = getIndex()->getObjectVersion();
2672 node->requestInfo = requestInfo;
2673 const Uint32 length = serializedDef.getSize() - startPos;
2674 if (unlikely(length > 0xFFFF)) {
2675 return QRY_DEFINITION_TOO_LARGE; //Query definition too large.
2676 } else {
2677 QueryNode::setOpLen(node->len, QueryNode::QN_LOOKUP, length);
2678 }
2679
2680 #ifdef __TRACE_SERIALIZATION
2681 ndbout << "Serialized index " << getInternalOpNo()-1 << " : ";
2682 for (Uint32 i = startPos; i < serializedDef.getSize(); i++){
2683 char buf[12];
2684 sprintf(buf, "%.8x", serializedDef.get(i));
2685 ndbout << buf << " ";
2686 }
2687 ndbout << endl;
2688 #endif
2689 } // End: Serialize unique index access
2690
2691 // Reserve memory for LookupNode, fill in contents later when
2692 // 'length' and 'requestInfo' has been calculated.
2693 Uint32 startPos = serializedDef.getSize();
2694 serializedDef.alloc(QN_LookupNode::NodeSize);
2695 Uint32 requestInfo = 0;
2696
2697 /**
2698 * NOTE: Order of sections within the optional part is fixed as:
2699 * Part1: 'NI_HAS_PARENT'
2700 * Part2: 'NI_KEY_PARAMS, NI_KEY_LINKED, NI_KEY_CONST'
2701 * PART3: 'NI_LINKED_ATTR ++
2702 */
2703
2704 // Optional part1: Append index as (single) parent op..
2705 { requestInfo |= DABits::NI_HAS_PARENT;
2706 Uint16Sequence parentSeq(serializedDef,1);
2707 parentSeq.append(getInternalOpNo()-1);
2708 parentSeq.finish();
2709 }
2710
2711 // Part2: Append projected NDB$PK column as index -> table linkage
2712 {
2713 requestInfo |= DABits::NI_KEY_LINKED;
2714 serializedDef.append(1U); // Length: Key pattern contains only the single PK column
2715 serializedDef.append(QueryPattern::colPk(0));
2716 }
2717
2718 // Part3: Columns required by SPJ to instantiate descendant child operations.
2719 requestInfo |= appendChildProjection(serializedDef);
2720
2721 // Fill in LookupNode contents (Already allocated, 'startPos' is our handle:
2722 QN_LookupNode* node = reinterpret_cast<QN_LookupNode*>(serializedDef.addr(startPos));
2723 if (unlikely(node==NULL)) {
2724 return Err_MemoryAlloc;
2725 }
2726 node->tableId = getTable().getObjectId();
2727 node->tableVersion = getTable().getObjectVersion();
2728 node->requestInfo = requestInfo;
2729 const Uint32 length = serializedDef.getSize() - startPos;
2730 if (unlikely(length > 0xFFFF)) {
2731 return QRY_DEFINITION_TOO_LARGE; //Query definition too large.
2732 } else {
2733 QueryNode::setOpLen(node->len, QueryNode::QN_LOOKUP, length);
2734 }
2735
2736 #ifdef __TRACE_SERIALIZATION
2737 ndbout << "Serialized node " << getInternalOpNo() << " : ";
2738 for (Uint32 i = startPos; i < serializedDef.getSize(); i++) {
2739 char buf[12];
2740 sprintf(buf, "%.8x", serializedDef.get(i));
2741 ndbout << buf << " ";
2742 }
2743 ndbout << endl;
2744 #endif
2745
2746 return 0;
2747 } // NdbQueryIndexOperationDefImpl::serializeOperation
2748
2749
NdbQueryScanOperationDefImpl(const NdbTableImpl & table,const NdbQueryOptionsImpl & options,const char * ident,Uint32 opNo,Uint32 internalOpNo,int & error)2750 NdbQueryScanOperationDefImpl::NdbQueryScanOperationDefImpl (
2751 const NdbTableImpl& table,
2752 const NdbQueryOptionsImpl& options,
2753 const char* ident,
2754 Uint32 opNo,
2755 Uint32 internalOpNo,
2756 int& error)
2757 : NdbQueryOperationDefImpl(table, options, ident, opNo, internalOpNo, error)
2758 {}
2759
2760 int
serialize(Uint32Buffer & serializedDef,const NdbTableImpl & tableOrIndex)2761 NdbQueryScanOperationDefImpl::serialize(Uint32Buffer& serializedDef,
2762 const NdbTableImpl& tableOrIndex)
2763 {
2764 bool isRoot = (getOpNo()==0);
2765
2766 // This method should only be invoked once.
2767 assert (!m_isPrepared);
2768 m_isPrepared = true;
2769 // Reserve memory for ScanFragNode, fill in contents later when
2770 // 'length' and 'requestInfo' has been calculated.
2771 Uint32 startPos = serializedDef.getSize();
2772 assert (QN_ScanFragNode::NodeSize==QN_ScanIndexNode::NodeSize);
2773 serializedDef.alloc(QN_ScanFragNode::NodeSize);
2774 Uint32 requestInfo = 0;
2775
2776 // Optional part1: Make list of parent nodes.
2777 requestInfo |= appendParentList (serializedDef);
2778
2779 // Part2: Append pattern for building upper/lower bounds.
2780 requestInfo |= appendBoundPattern(serializedDef);
2781
2782 // Part3: Columns required by SPJ to instantiate descendant child operations.
2783 requestInfo |= appendChildProjection(serializedDef);
2784
2785 // Part4: Pattern to creating a prune key for range scan
2786 requestInfo |= appendPrunePattern(serializedDef);
2787
2788 const Uint32 length = serializedDef.getSize() - startPos;
2789 if (unlikely(length > 0xFFFF))
2790 {
2791 return QRY_DEFINITION_TOO_LARGE; //Query definition too large.
2792 }
2793 // Fill in ScanFragNode/ScanIndexNode contents (Already allocated, 'startPos' is our handle:
2794 if (isRoot)
2795 {
2796 QN_ScanFragNode* node = reinterpret_cast<QN_ScanFragNode*>(serializedDef.addr(startPos));
2797 if (unlikely(node==NULL)) {
2798 return Err_MemoryAlloc;
2799 }
2800 node->tableId = tableOrIndex.getObjectId();
2801 node->tableVersion = tableOrIndex.getObjectVersion();
2802 node->requestInfo = requestInfo;
2803 QueryNode::setOpLen(node->len, QueryNode::QN_SCAN_FRAG, length);
2804 }
2805 else
2806 {
2807 QN_ScanIndexNode* node = reinterpret_cast<QN_ScanIndexNode*>(serializedDef.addr(startPos));
2808 if (unlikely(node==NULL)) {
2809 return Err_MemoryAlloc;
2810 }
2811 node->tableId = tableOrIndex.getObjectId();
2812 node->tableVersion = tableOrIndex.getObjectVersion();
2813 // Need NI_REPEAT_SCAN_RESULT if there are star-joined scans
2814 node->requestInfo = requestInfo | DABits::NI_REPEAT_SCAN_RESULT;
2815 QueryNode::setOpLen(node->len, QueryNode::QN_SCAN_INDEX, length);
2816 }
2817
2818 #ifdef __TRACE_SERIALIZATION
2819 ndbout << "Serialized node " << getInternalOpNo() << " : ";
2820 for(Uint32 i = startPos; i < serializedDef.getSize(); i++){
2821 char buf[12];
2822 sprintf(buf, "%.8x", serializedDef.get(i));
2823 ndbout << buf << " ";
2824 }
2825 ndbout << endl;
2826 #endif
2827 return 0;
2828 } // NdbQueryScanOperationDefImpl::serialize
2829
2830
2831 int
2832 NdbQueryTableScanOperationDefImpl
serializeOperation(Uint32Buffer & serializedDef)2833 ::serializeOperation(Uint32Buffer& serializedDef)
2834 {
2835 return NdbQueryScanOperationDefImpl::serialize(serializedDef, getTable());
2836 } // NdbQueryTableScanOperationDefImpl::serializeOperation
2837
2838
2839 int
2840 NdbQueryIndexScanOperationDefImpl
serializeOperation(Uint32Buffer & serializedDef)2841 ::serializeOperation(Uint32Buffer& serializedDef)
2842 {
2843 return NdbQueryScanOperationDefImpl::serialize(serializedDef, *m_index.getIndexTable());
2844 } // NdbQueryIndexScanOperationDefImpl::serializeOperation
2845
2846
2847 // Instantiate Vector templates
2848 template class Vector<NdbQueryOperationDefImpl*>;
2849 template class Vector<NdbQueryOperandImpl*>;
2850
2851 template class Vector<const NdbParamOperandImpl*>;
2852 template class Vector<const NdbColumnImpl*>;
2853
2854 #if 0
2855 /**********************************************
2856 * Simple hack for module test & experimenting
2857 **********************************************/
2858 #include <stdio.h>
2859 #include <assert.h>
2860
2861 int
2862 main(int argc, const char** argv)
2863 {
2864 printf("Hello, I am the unit test for NdbQueryBuilder\n");
2865
2866 printf("sizeof(NdbQueryOperationDef): %d\n", sizeof(NdbQueryOperationDef));
2867 printf("sizeof(NdbQueryLookupOperationDef): %d\n", sizeof(NdbQueryLookupOperationDef));
2868
2869 // Assert that interfaces *only* contain the pimpl pointer:
2870 assert (sizeof(NdbQueryOperationDef) == sizeof(NdbQueryOperationDefImpl*));
2871 assert (sizeof(NdbQueryLookupOperationDef) == sizeof(NdbQueryOperationDefImpl*));
2872 assert (sizeof(NdbQueryTableScanOperationDef) == sizeof(NdbQueryOperationDefImpl*));
2873 assert (sizeof(NdbQueryIndexScanOperationDef) == sizeof(NdbQueryOperationDefImpl*));
2874
2875 assert (sizeof(NdbQueryOperand) == sizeof(NdbQueryOperandImpl*));
2876 assert (sizeof(NdbConstOperand) == sizeof(NdbQueryOperandImpl*));
2877 assert (sizeof(NdbParamOperand) == sizeof(NdbQueryOperandImpl*));
2878 assert (sizeof(NdbLinkedOperand) == sizeof(NdbQueryOperandImpl*));
2879
2880 NdbQueryBuilder* const myBuilder= NdbQueryBuilder::create();
2881
2882 const NdbDictionary::Table *manager = (NdbDictionary::Table*)0xDEADBEAF;
2883 // const NdbDictionary::Index *ix = (NdbDictionary::Index*)0x11223344;
2884
2885 const NdbQueryDef* q1 = 0;
2886 {
2887 NdbQueryBuilder* qb = myBuilder;
2888
2889 const NdbQueryOperand* managerKey[] = // Manager is indexed om {"dept_no", "emp_no"}
2890 { qb->constValue("d005"), // dept_no = "d005"
2891 qb->constValue(110567), // emp_no = 110567
2892 0
2893 };
2894
2895 const NdbQueryLookupOperationDef *readManager = qb->readTuple(manager, managerKey);
2896 // if (readManager == NULL) APIERROR(myNdb.getNdbError());
2897 assert (readManager);
2898
2899 printf("readManager : %p\n", readManager);
2900 printf("Index : %p\n", readManager->getIndex());
2901 printf("Table : %p\n", readManager->getTable());
2902
2903 q1 = qb->prepare();
2904 // if (q1 == NULL) APIERROR(qb->getNdbError());
2905 assert (q1);
2906
2907 // Some operations are intentionally disallowed through private declaration
2908 // delete readManager;
2909 // NdbQueryLookupOperationDef illegalAssign = *readManager;
2910 // NdbQueryLookupOperationDef *illegalCopy1 = new NdbQueryLookupOperationDef(*readManager);
2911 // NdbQueryLookupOperationDef illegalCopy2(*readManager);
2912 }
2913 }
2914
2915 #endif
2916