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