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, 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 26 #ifndef NdbQueryBuilderImpl_H 27 #define NdbQueryBuilderImpl_H 28 29 /* Query-related error codes. */ 30 #define QRY_REQ_ARG_IS_NULL 4800 31 #define QRY_TOO_FEW_KEY_VALUES 4801 32 #define QRY_TOO_MANY_KEY_VALUES 4802 33 #define QRY_OPERAND_HAS_WRONG_TYPE 4803 34 #define QRY_CHAR_OPERAND_TRUNCATED 4804 35 #define QRY_NUM_OPERAND_RANGE 4805 36 #define QRY_MULTIPLE_PARENTS 4806 37 #define QRY_UNKONWN_PARENT 4807 38 #define QRY_UNKNOWN_COLUMN 4808 39 #define QRY_UNRELATED_INDEX 4809 40 #define QRY_WRONG_INDEX_TYPE 4810 41 #define QRY_OPERAND_ALREADY_BOUND 4811 42 #define QRY_DEFINITION_TOO_LARGE 4812 43 #define QRY_SEQUENTIAL_SCAN_SORTED 4813 44 #define QRY_RESULT_ROW_ALREADY_DEFINED 4814 45 #define QRY_HAS_ZERO_OPERATIONS 4815 46 #define QRY_IN_ERROR_STATE 4816 47 #define QRY_ILLEGAL_STATE 4817 48 #define QRY_WRONG_OPERATION_TYPE 4820 49 #define QRY_SCAN_ORDER_ALREADY_SET 4821 50 #define QRY_PARAMETER_HAS_WRONG_TYPE 4822 51 #define QRY_CHAR_PARAMETER_TRUNCATED 4823 52 #define QRY_MULTIPLE_SCAN_SORTED 4824 53 #define QRY_BATCH_SIZE_TOO_SMALL 4825 54 55 #ifdef __cplusplus 56 #include <Vector.hpp> 57 #include <Bitmask.hpp> 58 #include "NdbQueryBuilder.hpp" 59 #include "NdbIndexScanOperation.hpp" 60 #include "ndb_limits.h" 61 62 // Forward declared 63 class NdbTableImpl; 64 class NdbIndexImpl; 65 class NdbColumnImpl; 66 class NdbQueryBuilderImpl; 67 class NdbQueryDefImpl; 68 class NdbQueryOperationDefImpl; 69 class NdbQueryParamValue; 70 class NdbParamOperandImpl; 71 class NdbConstOperandImpl; 72 class NdbLinkedOperandImpl; 73 74 // For debuggging. 75 //#define TRACE_SERIALIZATION 76 77 /** A buffer for holding serialized data. 78 * 79 * Data is normaly appended to the end of this buffer by several variants 80 * of ::append(). A chunk of memory may also be allocated (at end of buffer) 81 * with ::alloc(). The buffer has a small local storage likely to be sufficent 82 * for most buffer usage. If required it will allocate a buffer extension to 83 * satisfy larger buffer requests. 84 * 85 * NOTE: When buffer grows, it contents may be relocated ta another memory area. 86 * Pointers returned to ::alloc'ed objects or ::addr() request are therefore 87 * not valid after another ::append() or ::alloc() has been performed. 88 * If pointer persistency is required, use ::getSize() to store the current 89 * end of buffer before the persistent object is allocated or appended. 90 * You may then later use 'size' as a handle to ::addr() to get the address. 91 * 92 * NOTE: If memory allocation fails during append / alloc, a 'memoryExhausted' state 93 * is set. Further allocation or append will then fail or be ignored. Before 94 * using the contents in the Uint32Buffer, always check ::isMemoryExhausted() 95 * to validate the contents of your buffer. 96 */ 97 class Uint32Buffer{ 98 public: 99 100 //#define TEST_Uint32Buffer 101 102 #if defined(TEST_Uint32Buffer) 103 STATIC_CONST(initSize = 1); // Small size to force test of buffer expand. 104 #else 105 STATIC_CONST(initSize = 32); // Initial buffer size, extend on demand but probably sufficent 106 #endif 107 Uint32Buffer()108 explicit Uint32Buffer(): 109 m_array(m_local), 110 m_avail(initSize), 111 m_size(0), 112 m_memoryExhausted(false), 113 m_bytesLeft(0) 114 {} 115 ~Uint32Buffer()116 ~Uint32Buffer() { 117 if (unlikely(m_array != m_local)) { 118 delete[] m_array; 119 } 120 } 121 122 /** 123 * Explicit release of buffer to shrink memory footprint. 124 */ releaseExtend()125 void releaseExtend() { 126 if (unlikely(m_array != m_local)) { 127 delete[] m_array; 128 } 129 m_array = NULL; 130 m_size = 0; 131 } 132 133 /** 134 * Allocate a buffer extension at end of this buffer. 135 * NOTE: Return NULL if allocation fails and set 136 * isMemoryExhausted. This will also cause further 137 * alloc() / append() to be skipped. 138 */ alloc(Uint32 count)139 Uint32* alloc(Uint32 count) { 140 Uint32 reqSize = m_size+count; 141 if(unlikely(reqSize >= m_avail)) { 142 if (unlikely(m_memoryExhausted)) { 143 return NULL; 144 } 145 #if defined(TEST_Uint32Buffer) 146 Uint32 newSize = reqSize; // -> Always expand on next alloc 147 #else 148 Uint32 newSize = reqSize*2; 149 #endif 150 // ndbout << "Uint32Buffer::alloc() Extend buffer from: " << m_avail 151 // << ", to: " << newSize << endl; 152 Uint32* newBuf = new Uint32[newSize]; 153 if (likely(newBuf!=NULL)) { 154 assert(newBuf); 155 memcpy (newBuf, m_array, m_size*sizeof(Uint32)); 156 if (m_array != m_local) { 157 delete[] m_array; 158 } 159 m_array = newBuf; 160 m_avail = static_cast<Uint32>(newSize); 161 } else { 162 m_size = m_avail; 163 m_memoryExhausted = true; 164 return NULL; 165 } 166 } 167 Uint32* extend = &m_array[m_size]; 168 m_size += static_cast<Uint32>(count); 169 return extend; 170 } 171 172 /** Put the idx'th element already allocated. 173 */ put(Uint32 idx,Uint32 value)174 void put(Uint32 idx, Uint32 value) { 175 assert(idx < m_size); 176 m_array[idx] = value; 177 } 178 179 /** append 'src' word to end of this buffer 180 */ append(const Uint32 src)181 void append(const Uint32 src) { 182 m_bytesLeft = 0; 183 if (likely(m_size < m_avail)) { 184 m_array[m_size++] = src; 185 } else { 186 Uint32* dst = alloc(1); 187 if (likely(dst!=NULL)) 188 *dst = src; 189 } 190 } 191 192 /** append 'src' buffer to end of this buffer 193 */ append(const Uint32Buffer & src)194 void append(const Uint32Buffer& src) { 195 assert (!src.isMemoryExhausted()); 196 m_bytesLeft = 0; 197 Uint32 len = src.getSize(); 198 if (likely(len > 0)) { 199 Uint32* dst = alloc(len); 200 if (likely(dst!=NULL)) { 201 memcpy(dst, src.addr(), len*sizeof(Uint32)); 202 } 203 } 204 } 205 206 /** append 'src' *bytes* to end of this buffer 207 * Zero pad possibly odd bytes in last Uint32 word 208 */ appendBytes(const void * src,Uint32 len)209 void appendBytes(const void* src, Uint32 len) { 210 if (likely(len > 0)) { 211 Uint32 wordCount = 212 static_cast<Uint32>((len + sizeof(Uint32)-1 - m_bytesLeft) 213 / sizeof(Uint32)); 214 Uint32* dst = alloc(wordCount); 215 if (likely(dst!=NULL)) { 216 // Copy src 217 Uint8* const start = reinterpret_cast<Uint8*>(dst) - m_bytesLeft; 218 memcpy(start, src, len); 219 m_bytesLeft = (m_bytesLeft - len) % sizeof(Uint32); 220 // Make sure that any trailing bytes in the last word are zero. 221 bzero(start + len, m_bytesLeft); 222 } 223 } 224 } 225 226 /** Skip remaining bytes in m_array[m_size-1], so that a subsequent 227 * appendBytes() starts at a word boundary.*/ skipRestOfWord()228 void skipRestOfWord() 229 { m_bytesLeft = 0; } 230 addr(Uint32 idx=0)231 Uint32* addr(Uint32 idx=0) { 232 return (likely(!m_memoryExhausted && m_size>idx)) ?&m_array[idx] :NULL; 233 } addr(Uint32 idx=0) const234 const Uint32* addr(Uint32 idx=0) const { 235 return (likely(!m_memoryExhausted && m_size>idx)) ?&m_array[idx] :NULL; 236 } 237 238 /** Get the idx'th element. Make sure there is space for 'count' elements.*/ get(Uint32 idx) const239 Uint32 get(Uint32 idx) const { 240 assert(idx < m_size); 241 return m_array[idx]; 242 } 243 244 /** Check for possible memory alloc failure during build. */ isMemoryExhausted() const245 bool isMemoryExhausted() const { 246 return m_memoryExhausted; 247 } 248 getSize() const249 Uint32 getSize() const { 250 return m_size; 251 } 252 253 private: 254 /** Should not be copied, nor assigned.*/ 255 Uint32Buffer(Uint32Buffer&); 256 Uint32Buffer& operator=(Uint32Buffer&); 257 258 private: 259 Uint32 m_local[initSize]; // Initial static bufferspace 260 Uint32* m_array; // Refers m_local initially, or extended large buffer 261 Uint32 m_avail; // Available buffer space 262 Uint32 m_size; // Actuall size <= m_avail 263 bool m_memoryExhausted; 264 /** Number of remaining bytes (0-3) in m_array[m_size-1].*/ 265 Uint32 m_bytesLeft; 266 }; 267 268 269 class NdbQueryOptionsImpl 270 { 271 friend class NdbQueryOptions; 272 friend class NdbQueryOperationDefImpl; 273 274 public: NdbQueryOptionsImpl()275 explicit NdbQueryOptionsImpl() 276 : m_matchType(NdbQueryOptions::MatchAll), 277 m_scanOrder(NdbQueryOptions::ScanOrdering_void), 278 m_parent(NULL), 279 m_interpretedCode(NULL) 280 {}; 281 NdbQueryOptionsImpl(const NdbQueryOptionsImpl&); 282 ~NdbQueryOptionsImpl(); 283 284 private: 285 NdbQueryOptions::MatchType m_matchType; 286 NdbQueryOptions::ScanOrdering m_scanOrder; 287 NdbQueryOperationDefImpl* m_parent; 288 const NdbInterpretedCode* m_interpretedCode; 289 290 /** 291 * Assign NdbInterpretedCode by taking a deep copy of 'src' 292 * @return possible error code. 293 */ 294 int copyInterpretedCode(const NdbInterpretedCode& src); 295 296 NdbQueryOptionsImpl&operator=(const NdbQueryOptionsImpl&); // Not impl. 297 }; 298 299 300 //////////////////////////////////////////////// 301 // Implementation of NdbQueryOperation interface 302 //////////////////////////////////////////////// 303 304 class NdbQueryOperationDefImpl 305 { 306 friend class NdbQueryOperationDef; 307 friend class NdbQueryOperationImpl; 308 friend class NdbQueryImpl; 309 310 public: 311 312 struct IndexBound { // Limiting 'bound ' definition for indexScan 313 NdbQueryOperandImpl* low[MAX_ATTRIBUTES_IN_INDEX]; 314 NdbQueryOperandImpl* high[MAX_ATTRIBUTES_IN_INDEX]; 315 Uint32 lowKeys, highKeys; 316 bool lowIncl, highIncl; 317 }; 318 319 /* Currently only a single parent is supported */ getNoOfParentOperations() const320 Uint32 getNoOfParentOperations() const 321 { return (m_parent) ? 1 : 0; } 322 getParentOperation(Uint32 i) const323 NdbQueryOperationDefImpl& getParentOperation(Uint32 i) const 324 { assert(i==0 && m_parent!=NULL); 325 return *m_parent; 326 } 327 getParentOperation() const328 NdbQueryOperationDefImpl* getParentOperation() const 329 { return m_parent; 330 } 331 getNoOfChildOperations() const332 Uint32 getNoOfChildOperations() const 333 { return m_children.size(); } 334 getChildOperation(Uint32 i) const335 NdbQueryOperationDefImpl& getChildOperation(Uint32 i) const 336 { return *m_children[i]; } 337 getTable() const338 const NdbTableImpl& getTable() const 339 { return m_table; } 340 getName() const341 const char* getName() const 342 { return m_ident; } 343 getMatchType() const344 enum NdbQueryOptions::MatchType getMatchType() const 345 { return m_options.m_matchType; } 346 getOrdering() const347 enum NdbQueryOptions::ScanOrdering getOrdering() const 348 { return m_options.m_scanOrder; } 349 getInterpretedCode() const350 const NdbInterpretedCode* getInterpretedCode() const 351 { return m_options.m_interpretedCode; } 352 assignQueryOperationId(Uint32 & nodeId)353 Uint32 assignQueryOperationId(Uint32& nodeId) 354 { if (getType()==NdbQueryOperationDef::UniqueIndexAccess) nodeId++; 355 m_id = nodeId++; 356 return m_id; 357 } 358 359 // Establish a linked parent <-> child relationship with this operation 360 int linkWithParent(NdbQueryOperationDefImpl* parentOp); 361 362 /** 363 * Register a linked reference to a column from operation 364 * @param[in] column Column to refer. 365 * @param[out] error Possible error code. 366 * @return position in list of refered columns available from 367 * this (parent) operation. Child ops later refer linked 368 * columns by its position in this list. 369 */ 370 Uint32 addColumnRef(const NdbColumnImpl* column, int& error); 371 372 /** 373 * Register a param operand which is refered by this operation. 374 * Param values are supplied pr. operation when code is serialized. 375 * @param[in] param Parameter to add. 376 * @return Possible error code. 377 */ 378 int addParamRef(const NdbParamOperandImpl* param); 379 getNoOfParameters() const380 Uint32 getNoOfParameters() const 381 { return m_params.size(); } 382 getParameter(Uint32 ix) const383 const NdbParamOperandImpl& getParameter(Uint32 ix) const 384 { return *m_params[ix]; } 385 getIndex() const386 virtual const NdbIndexImpl* getIndex() const 387 { return NULL; } 388 getKeyOperands() const389 virtual const NdbQueryOperandImpl* const* getKeyOperands() const 390 { return NULL; } 391 getBounds() const392 virtual const IndexBound* getBounds() const 393 { return NULL; } 394 395 // Return 'true' is query type is a multi-row scan 396 virtual bool isScanOperation() const = 0; 397 398 virtual const NdbQueryOperationDef& getInterface() const = 0; 399 400 /** Make a serialized representation of this operation, corresponding to 401 * the struct QueryNode type. 402 * @return Possible error code. 403 */ 404 virtual int serializeOperation(Uint32Buffer& serializedTree) = 0; 405 406 /** Find the projection that should be sent to the SPJ block. This should 407 * contain the attributes needed to instantiate all child operations. 408 */ getSPJProjection() const409 const Vector<const NdbColumnImpl*>& getSPJProjection() const { 410 return m_spjProjection; 411 } 412 checkPrunable(const Uint32Buffer & keyInfo,Uint32 shortestBound,bool & isPruned,Uint32 & hashValue) const413 virtual int checkPrunable(const Uint32Buffer& keyInfo, 414 Uint32 shortestBound, 415 bool& isPruned, 416 Uint32& hashValue) const { 417 isPruned = false; 418 return 0; 419 } 420 421 virtual ~NdbQueryOperationDefImpl(); 422 423 protected: 424 explicit NdbQueryOperationDefImpl (const NdbTableImpl& table, 425 const NdbQueryOptionsImpl& options, 426 const char* ident, 427 Uint32 ix, 428 int& error); 429 public: 430 // Get the ordinal position of this operation within the query def. getQueryOperationIx() const431 Uint32 getQueryOperationIx() const 432 { return m_ix; } 433 434 // Get id of node as known inside queryTree getQueryOperationId() const435 Uint32 getQueryOperationId() const 436 { return m_id; } 437 438 // Get type of query operation 439 virtual NdbQueryOperationDef::Type getType() const = 0; 440 441 /** Print query tree graph to trace file (using recursion). 442 * @param depth Number of ancestor nodes that this node has. 443 * @param hasMoreSiblingsMask The n'th bit should be set if the n'th ancestor 444 * (counted from the root) has more sibling nodes. 445 */ 446 void printTree( 447 Uint32 depth, 448 Bitmask<(NDB_SPJ_MAX_TREE_NODES+31)/32> hasMoreSiblingsMask) const; 449 450 protected: 451 // QueryTree building: 452 // Append list of parent nodes to serialized code 453 Uint32 appendParentList(Uint32Buffer& serializedDef) const; 454 455 // Append list of columns required by SPJ to instantiate child operations. 456 Uint32 appendChildProjection(Uint32Buffer& serializedDef) const; 457 458 protected: 459 /** True if enclosing query has been prepared.*/ 460 bool m_isPrepared; 461 462 /** 463 * True if the projection for instantiating child operations contains any 464 * disk columns. 465 */ 466 bool m_diskInChildProjection; 467 468 private: 469 bool isChildOf(const NdbQueryOperationDefImpl* parentOp) const; 470 471 /** 472 * Register a linked child refering specified operation 473 * @param[in] child Child operation to add. 474 * @return Possible error code. 475 */ 476 int addChild(NdbQueryOperationDefImpl* child); 477 478 // Remove a linked child refering specified operation 479 void removeChild(const NdbQueryOperationDefImpl*); 480 481 private: 482 const NdbTableImpl& m_table; 483 const char* const m_ident; // Optional name specified by aplication 484 const Uint32 m_ix; // Index of this operation within operation array 485 Uint32 m_id; // Operation id when materialized into queryTree. 486 // If op has index, index id is 'm_id-1'. 487 488 // Optional (or default) options specified when building query: 489 // - Scan order which may specify ascending or descending scan order 490 // - Match type used for hinting on optimal inner-, outer-, semijoin exec. 491 const NdbQueryOptionsImpl m_options; 492 493 // parent pointer & child ptr. vector contains dependencies 494 // as defined with linkedValues 495 NdbQueryOperationDefImpl* m_parent; 496 Vector<NdbQueryOperationDefImpl*> m_children; 497 498 // Params required by this operation 499 Vector<const NdbParamOperandImpl*> m_params; 500 501 // Column from this operation required by its child operations 502 Vector<const NdbColumnImpl*> m_spjProjection; 503 }; // class NdbQueryOperationDefImpl 504 505 506 class NdbQueryScanOperationDefImpl : 507 public NdbQueryOperationDefImpl 508 { 509 public: 510 explicit NdbQueryScanOperationDefImpl ( 511 const NdbTableImpl& table, 512 const NdbQueryOptionsImpl& options, 513 const char* ident, 514 Uint32 ix, 515 int& error); 516 isScanOperation() const517 virtual bool isScanOperation() const 518 { return true; } 519 520 protected: 521 int serialize(Uint32Buffer& serializedDef, 522 const NdbTableImpl& tableOrIndex); 523 524 // Append pattern for creating complete range bounds to serialized code appendBoundPattern(Uint32Buffer & serializedDef) const525 virtual Uint32 appendBoundPattern(Uint32Buffer& serializedDef) const 526 { return 0; } 527 appendPrunePattern(Uint32Buffer & serializedDef) const528 virtual Uint32 appendPrunePattern(Uint32Buffer& serializedDef) const 529 { return 0; } 530 531 }; // class NdbQueryScanOperationDefImpl 532 533 534 class NdbQueryIndexScanOperationDefImpl : public NdbQueryScanOperationDefImpl 535 { 536 friend class NdbQueryBuilder; // Allow privat access from builder interface 537 538 public: getIndex() const539 virtual const NdbIndexImpl* getIndex() const 540 { return &m_index; } 541 542 virtual int serializeOperation(Uint32Buffer& serializedDef); 543 getInterface() const544 virtual const NdbQueryIndexScanOperationDef& getInterface() const 545 { return m_interface; } 546 getType() const547 virtual NdbQueryOperationDef::Type getType() const 548 { return NdbQueryOperationDef::OrderedIndexScan; } 549 550 virtual int checkPrunable(const Uint32Buffer& keyInfo, 551 Uint32 shortestBound, 552 bool& isPruned, 553 Uint32& hashValue) const; 554 getBounds() const555 virtual const IndexBound* getBounds() const 556 { return &m_bound; } 557 558 protected: 559 // Append pattern for creating complete range bounds to serialized code 560 virtual Uint32 appendBoundPattern(Uint32Buffer& serializedDef) const; 561 562 virtual Uint32 appendPrunePattern(Uint32Buffer& serializedDef) const; 563 564 private: 565 566 explicit NdbQueryIndexScanOperationDefImpl ( 567 const NdbIndexImpl& index, 568 const NdbTableImpl& table, 569 const NdbQueryIndexBound* bound, 570 const NdbQueryOptionsImpl& options, 571 const char* ident, 572 Uint32 ix, 573 int& error); 574 575 // Append pattern for creating a single bound value to serialized code 576 Uint32 appendBoundValue( Uint32Buffer& serializedDef, 577 NdbIndexScanOperation::BoundType type, 578 const NdbQueryOperandImpl* value, 579 int& paramCnt) const; 580 581 private: 582 NdbQueryIndexScanOperationDef m_interface; 583 const NdbIndexImpl& m_index; 584 585 /** True if there is a set of bounds.*/ 586 IndexBound m_bound; 587 }; // class NdbQueryIndexScanOperationDefImpl 588 589 590 class NdbQueryDefImpl 591 { 592 friend class NdbQueryDef; 593 594 public: 595 explicit NdbQueryDefImpl(const Vector<NdbQueryOperationDefImpl*>& operations, 596 const Vector<NdbQueryOperandImpl*>& operands, 597 int& error); 598 ~NdbQueryDefImpl(); 599 600 // Entire query is a scan iff root operation is scan. 601 // May change in the future as we implement more complicated SPJ operations. isScanQuery() const602 bool isScanQuery() const 603 { return m_operations[0]->isScanOperation(); } 604 605 NdbQueryDef::QueryType getQueryType() const; 606 getNoOfOperations() const607 Uint32 getNoOfOperations() const 608 { return m_operations.size(); } 609 610 // Get a specific NdbQueryOperationDef by ident specified 611 // when the NdbQueryOperationDef was created. getQueryOperation(Uint32 index) const612 const NdbQueryOperationDefImpl& getQueryOperation(Uint32 index) const 613 { return *m_operations[index]; } 614 615 const NdbQueryOperationDefImpl* getQueryOperation(const char* ident) const; 616 getInterface() const617 const NdbQueryDef& getInterface() const 618 { return m_interface; } 619 620 /** Get serialized representation of query definition.*/ getSerialized()621 Uint32Buffer& getSerialized() 622 { return m_serializedDef; } 623 624 /** Get serialized representation of query definition.*/ getSerialized() const625 const Uint32Buffer& getSerialized() const 626 { return m_serializedDef; } 627 628 private: 629 NdbQueryDef m_interface; 630 631 Vector<NdbQueryOperationDefImpl*> m_operations; 632 Vector<NdbQueryOperandImpl*> m_operands; 633 Uint32Buffer m_serializedDef; 634 }; // class NdbQueryDefImpl 635 636 637 class NdbQueryBuilderImpl 638 { 639 friend class NdbQueryBuilder; 640 641 public: 642 ~NdbQueryBuilderImpl(); 643 explicit NdbQueryBuilderImpl(); 644 645 const NdbQueryDefImpl* prepare(); 646 647 const NdbError& getNdbError() const; 648 649 void setErrorCode(int aErrorCode); 650 651 private: hasError() const652 bool hasError() const 653 { return m_hasError; } 654 655 /** 656 * Add an operand to m_operands. Set an error code if operand 657 * is null or if adding it to m_operands fails. 658 * @param[in] operand to add (may be NULL). 659 * @return Operand interface (or NULL if there was an error.) 660 */ 661 NdbQueryOperand* addOperand(NdbQueryOperandImpl* operand); 662 663 /** 664 * Take ownership of specified object: From now on it is the 665 * responsibility of this NdbQueryBuilderImpl to manage the 666 * lifetime of the object. If takeOwnership() fails, the 667 * specified object is deleted before it returns. 668 * @param[in] operand to take ownership for (may be NULL). 669 * @return 0 if ok, else there has been an 'Err_MemoryAlloc' 670 */ 671 int takeOwnership(NdbQueryOperandImpl*); 672 int takeOwnership(NdbQueryOperationDefImpl*); 673 674 bool contains(const NdbQueryOperationDefImpl*); 675 676 NdbQueryBuilder m_interface; 677 NdbError m_error; 678 679 Vector<NdbQueryOperationDefImpl*> m_operations; 680 Vector<NdbQueryOperandImpl*> m_operands; 681 Uint32 m_paramCnt; 682 /** True if there was an error that prevents further use of this object.*/ 683 bool m_hasError; 684 }; // class NdbQueryBuilderImpl 685 686 687 ////////////////////////////////////////////// 688 // Implementation of NdbQueryOperand interface 689 ////////////////////////////////////////////// 690 691 // Baseclass for the QueryOperand implementation 692 class NdbQueryOperandImpl 693 { 694 friend class NdbQueryBuilderImpl; 695 public: 696 697 /** The type of an operand. This corresponds to the set of subclasses 698 * of NdbQueryOperandImpl. 699 */ 700 enum Kind { 701 Linked, 702 Param, 703 Const 704 }; 705 getColumn() const706 const NdbColumnImpl* getColumn() const 707 { return m_column; } 708 bindOperand(const NdbColumnImpl & column,NdbQueryOperationDefImpl & operation)709 virtual int bindOperand(const NdbColumnImpl& column, 710 NdbQueryOperationDefImpl& operation) 711 { if (m_column && m_column != &column) 712 // Already bounded to a different column 713 return QRY_OPERAND_ALREADY_BOUND; 714 m_column = &column; 715 return 0; 716 } 717 getKind() const718 Kind getKind() const 719 { return m_kind; } 720 721 virtual NdbQueryOperand& getInterface() = 0; 722 723 protected: 724 friend NdbQueryBuilderImpl::~NdbQueryBuilderImpl(); 725 friend NdbQueryDefImpl::~NdbQueryDefImpl(); 726 ~NdbQueryOperandImpl()727 virtual ~NdbQueryOperandImpl(){}; 728 NdbQueryOperandImpl(Kind kind)729 NdbQueryOperandImpl(Kind kind) 730 : m_column(0), 731 m_kind(kind) 732 {} 733 734 protected: 735 const NdbColumnImpl* m_column; // Initial NULL, assigned w/ bindOperand() 736 737 /** This is used to tell the type of an NdbQueryOperand. This allow safe 738 * downcasting to a subclass. 739 */ 740 const Kind m_kind; 741 }; // class NdbQueryOperandImpl 742 743 744 class NdbLinkedOperandImpl : public NdbQueryOperandImpl 745 { 746 friend class NdbQueryBuilder; // Allow privat access from builder interface 747 748 public: getParentOperation() const749 const NdbQueryOperationDefImpl& getParentOperation() const 750 { return m_parentOperation; } 751 752 // 'LinkedSrc' is index into parent op's spj-projection list where 753 // the refered column value is available getLinkedColumnIx() const754 Uint32 getLinkedColumnIx() const 755 { return m_parentColumnIx; } 756 getParentColumn() const757 const NdbColumnImpl& getParentColumn() const 758 { return *m_parentOperation.getSPJProjection()[m_parentColumnIx]; } 759 getInterface()760 virtual NdbQueryOperand& getInterface() 761 { return m_interface; } 762 763 virtual int bindOperand(const NdbColumnImpl& column, 764 NdbQueryOperationDefImpl& operation); 765 766 private: NdbLinkedOperandImpl(NdbQueryOperationDefImpl & parent,Uint32 columnIx)767 NdbLinkedOperandImpl (NdbQueryOperationDefImpl& parent, 768 Uint32 columnIx) 769 : NdbQueryOperandImpl(Linked), 770 m_interface(*this), 771 m_parentOperation(parent), 772 m_parentColumnIx(columnIx) 773 {} 774 775 NdbLinkedOperand m_interface; 776 NdbQueryOperationDefImpl& m_parentOperation; 777 const Uint32 m_parentColumnIx; 778 }; // class NdbLinkedOperandImpl 779 780 781 class NdbParamOperandImpl : public NdbQueryOperandImpl 782 { 783 friend class NdbQueryBuilder; // Allow privat access from builder interface 784 785 public: getName() const786 const char* getName() const 787 { return m_name; } 788 getParamIx() const789 Uint32 getParamIx() const 790 { return m_paramIx; } 791 getInterface()792 virtual NdbQueryOperand& getInterface() 793 { return m_interface; } 794 795 virtual int bindOperand(const NdbColumnImpl& column, 796 NdbQueryOperationDefImpl& operation); 797 798 private: NdbParamOperandImpl(const char * name,Uint32 paramIx)799 NdbParamOperandImpl (const char* name, Uint32 paramIx) 800 : NdbQueryOperandImpl(Param), 801 m_interface(*this), 802 m_name(name), 803 m_paramIx(paramIx) 804 {} 805 806 NdbParamOperand m_interface; 807 const char* const m_name; // Optional parameter name or NULL 808 const Uint32 m_paramIx; 809 }; // class NdbParamOperandImpl 810 811 812 class NdbConstOperandImpl : public NdbQueryOperandImpl 813 { 814 friend class NdbQueryBuilder; // Allow privat access from builder interface 815 public: getSizeInBytes() const816 Uint32 getSizeInBytes() const 817 { return m_converted.len; } getAddr() const818 const void* getAddr() const 819 { return likely(m_converted.buffer==NULL) ? &m_converted.val : m_converted.buffer; } 820 getInterface()821 virtual NdbQueryOperand& getInterface() 822 { return m_interface; } 823 824 virtual int bindOperand(const NdbColumnImpl& column, 825 NdbQueryOperationDefImpl& operation); 826 827 protected: NdbConstOperandImpl()828 NdbConstOperandImpl () 829 : NdbQueryOperandImpl(Const), 830 m_converted(), 831 m_interface(*this) 832 {} 833 834 #define UNDEFINED_CONVERSION \ 835 { return QRY_OPERAND_HAS_WRONG_TYPE; } 836 837 virtual int convertUint8() UNDEFINED_CONVERSION; 838 virtual int convertInt8() UNDEFINED_CONVERSION; 839 virtual int convertUint16() UNDEFINED_CONVERSION; 840 virtual int convertInt16() UNDEFINED_CONVERSION; 841 virtual int convertUint24() UNDEFINED_CONVERSION; 842 virtual int convertInt24() UNDEFINED_CONVERSION; 843 virtual int convertUint32() UNDEFINED_CONVERSION; 844 virtual int convertInt32() UNDEFINED_CONVERSION; 845 virtual int convertUint64() UNDEFINED_CONVERSION; 846 virtual int convertInt64() UNDEFINED_CONVERSION; 847 virtual int convertFloat() UNDEFINED_CONVERSION; 848 virtual int convertDouble() UNDEFINED_CONVERSION 849 850 virtual int convertUDec() UNDEFINED_CONVERSION; 851 virtual int convertDec() UNDEFINED_CONVERSION; 852 853 virtual int convertBit() UNDEFINED_CONVERSION; 854 virtual int convertChar() UNDEFINED_CONVERSION; 855 virtual int convertVChar() UNDEFINED_CONVERSION; 856 virtual int convertLVChar() UNDEFINED_CONVERSION; 857 virtual int convertBin() UNDEFINED_CONVERSION; 858 virtual int convertVBin() UNDEFINED_CONVERSION; 859 virtual int convertLVBin() UNDEFINED_CONVERSION; 860 861 virtual int convertDate() UNDEFINED_CONVERSION; 862 virtual int convertDatetime() UNDEFINED_CONVERSION; 863 virtual int convertTime() UNDEFINED_CONVERSION; 864 virtual int convertYear() UNDEFINED_CONVERSION; 865 virtual int convertTimestamp() UNDEFINED_CONVERSION; 866 867 virtual int convert2ColumnType(); 868 869 /** Values converted to datatype format as expected by bound column 870 * (available through ::getColumn()) 871 */ 872 class ConvertedValue { 873 public: ConvertedValue()874 ConvertedValue() : len(0), buffer(NULL) {}; ~ConvertedValue()875 ~ConvertedValue() { 876 if (buffer) delete[] ((char*)buffer); 877 }; 878 getCharBuffer(Uint32 size)879 char* getCharBuffer(Uint32 size) { 880 char* dst = val.shortChar; 881 if (unlikely(size > sizeof(val.shortChar))) { 882 dst = new char[size]; 883 buffer = dst; 884 } 885 len = size; 886 return dst; 887 } 888 889 STATIC_CONST(maxShortChar = 32); 890 891 union 892 { 893 Uint8 uint8; 894 Int8 int8; 895 Uint16 uint16; 896 Int16 int16; 897 Uint32 uint32; 898 Int32 int32; 899 Uint64 uint64; 900 Int64 int64; 901 902 double dbl; 903 float flt; 904 905 char shortChar[maxShortChar]; 906 } val; 907 908 Uint32 len; 909 void* buffer; // Optional; storage for converted value 910 } m_converted; 911 912 private: 913 NdbConstOperand m_interface; 914 }; // class NdbConstOperandImpl 915 916 917 #endif /* __cplusplus */ 918 #endif 919