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