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