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 Street, Fifth Floor, Boston, MA 02110-1301, USA */ 23 24 #ifndef NdbQueryOperationImpl_H 25 #define NdbQueryOperationImpl_H 26 27 #include "NdbQueryOperation.hpp" 28 #include "NdbQueryBuilderImpl.hpp" 29 #include "NdbIndexScanOperation.hpp" 30 #include <NdbError.hpp> 31 #include <ndb_limits.h> 32 #include <Vector.hpp> 33 34 // Forward declarations 35 class NdbTableImpl; 36 class NdbIndexImpl; 37 class NdbApiSignal; 38 class NdbResultStream; 39 class NdbParamOperand; 40 class NdbTransaction; 41 class NdbReceiver; 42 class NdbOut; 43 class NdbRootFragment; 44 45 /** 46 * This class simplifies the task of allocating memory for many instances 47 * of the same type at once and then constructing them later. 48 */ 49 class NdbBulkAllocator 50 { 51 public: 52 /** 53 * @param[in] objSize Size (in bytes) of each object. 54 */ 55 explicit NdbBulkAllocator(size_t objSize); ~NdbBulkAllocator()56 ~NdbBulkAllocator() 57 { reset(); }; 58 59 /** 60 * Allocate memory for a number of objects from the heap. 61 * @param[in] maxObjs The maximal number of objects this instance should 62 * accomodate. 63 * @return 0 or possible error code. 64 */ 65 int init(Uint32 maxObjs); 66 67 /** Release allocated memory to heap and reset *this to initial state.*/ 68 void reset(); 69 70 /** 71 * Get an area large enough to hold 'noOfObjs' objects. 72 * @return The memory area. 73 */ 74 void* allocObjMem(Uint32 noOfObjs); 75 private: 76 /** An end marker for checking for buffer overrun.*/ 77 static const char endMarker = -15; 78 79 /** Size of each object (in bytes).*/ 80 const size_t m_objSize; 81 82 /** The number of objects this instance can accomodate.*/ 83 Uint32 m_maxObjs; 84 85 /** The allocated memory area.*/ 86 char* m_buffer; 87 88 /** The number of object areas allocated so far.*/ 89 Uint32 m_nextObjNo; 90 91 // No copying. 92 NdbBulkAllocator(const NdbBulkAllocator&); 93 NdbBulkAllocator& operator= (const NdbBulkAllocator&); 94 }; 95 96 /** This class is the internal implementation of the interface defined by 97 * NdbQuery. This class should thus not be visible to the application 98 * programmer. @see NdbQuery.*/ 99 class NdbQueryImpl { 100 101 /* NdbQueryOperations are allowed to access it containing query */ 102 friend class NdbQueryOperationImpl; 103 104 /** For debugging.*/ 105 friend NdbOut& operator<<(NdbOut& out, const class NdbQueryOperationImpl&); 106 107 public: 108 /** Factory method which instantiate a query from its definition. 109 (There is no public constructor.)*/ 110 static NdbQueryImpl* buildQuery(NdbTransaction& trans, 111 const NdbQueryDefImpl& queryDef); 112 113 /** Return number of operations in query.*/ 114 Uint32 getNoOfOperations() const; 115 116 /** 117 * return number of leaf-operations 118 */ 119 Uint32 getNoOfLeafOperations() const; 120 121 // Get a specific NdbQueryOperation instance by ident specified 122 // when the NdbQueryOperationDef was created. 123 NdbQueryOperationImpl& getQueryOperation(Uint32 ident) const; 124 NdbQueryOperationImpl* getQueryOperation(const char* ident) const; 125 // Consider to introduce these as convenient shortcuts 126 //NdbQueryOperationDefImpl& getQueryOperationDef(Uint32 ident) const; 127 //NdbQueryOperationDefImpl* getQueryOperationDef(const char* ident) const; 128 129 /** Return number of parameter operands in query.*/ 130 Uint32 getNoOfParameters() const; 131 const NdbParamOperand* getParameter(const char* name) const; 132 const NdbParamOperand* getParameter(Uint32 num) const; 133 134 /** Get the next tuple(s) from the global cursor on the query. 135 * @param fetchAllowed If true, the method may block while waiting for more 136 * results to arrive. Otherwise, the method will return immediately if no more 137 * results are buffered in the API. 138 * @param forceSend FIXME: Describe this. 139 * @return 140 * - NextResult_error (-1): if unsuccessful,<br> 141 * - NextResult_gotRow (0): if another tuple was received, and<br> 142 * - NextResult_scanComplete (1): if there are no more tuples to scan. 143 * - NextResult_bufferEmpty (2): if there are no more cached records 144 * in NdbApi 145 * @see NdbQueryOperation::nextResult() 146 */ 147 NdbQuery::NextResultOutcome nextResult(bool fetchAllowed, bool forceSend); 148 149 /** Close query: 150 * - Release datanode resources, 151 * - Discard pending result sets, 152 * - Delete internal buffer and structures for receiving results. 153 * - Disconnect with NdbQueryDef - it might now be destructed . 154 */ 155 int close(bool forceSend); 156 157 /** Deallocate 'this' NdbQuery object and its NdbQueryOperation objects. 158 * If not already closed, it will also ::close() the NdbQuery. 159 */ 160 void release(); 161 getNdbTransaction() const162 NdbTransaction& getNdbTransaction() const 163 { return m_transaction; } 164 165 const NdbError& getNdbError() const; 166 167 void setErrorCode(int aErrorCode); 168 169 /** Assign supplied parameter values to the parameter placeholders 170 * created when the query was defined. 171 * Values are *copied* into this NdbQueryImpl object: 172 * Memory location used as source for parameter values don't have 173 * to be valid after this assignment. 174 */ 175 int assignParameters(const NdbQueryParamValue paramValues[]); 176 177 int setBound(const NdbRecord *keyRecord, 178 const NdbIndexScanOperation::IndexBound *bound); 179 180 /** Prepare for execution. 181 * @return possible error code. 182 */ 183 int prepareSend(); 184 185 /** Send prepared signals from this NdbQuery to start execution 186 * @return #signals sent, -1 if error. 187 */ 188 int doSend(int aNodeId, bool lastFlag); 189 getInterface()190 NdbQuery& getInterface() 191 { return m_interface; } 192 193 /** Get next query in same transaction.*/ getNext() const194 NdbQueryImpl* getNext() const 195 { return m_next; } 196 setNext(NdbQueryImpl * next)197 void setNext(NdbQueryImpl* next) 198 { m_next = next; } 199 200 /** Get the (transaction independent) definition of this query. */ getQueryDef() const201 const NdbQueryDefImpl& getQueryDef() const 202 { 203 assert(m_queryDef); 204 return *m_queryDef; 205 } 206 207 /** Process TCKEYCONF message. Return true if query is complete. */ 208 bool execTCKEYCONF(); 209 210 /** Process SCAN_TABCONF w/ EndOfData which is a 'Close Scan Reply'. */ 211 void execCLOSE_SCAN_REP(int errorCode, bool needClose); 212 213 /** Determines if query has completed and may be garbage collected 214 * A query is not considder complete until the client has 215 * called the ::close() or ::release() method on it. 216 */ hasCompleted() const217 bool hasCompleted() const 218 { return (m_state == Closed); 219 } 220 221 /** 222 * Mark this query as the first query or operation in a new transaction. 223 * This should only be called for queries where root operation is a lookup. 224 */ setStartIndicator()225 void setStartIndicator() 226 { 227 assert(!getQueryDef().isScanQuery()); 228 m_startIndicator = true; 229 } 230 231 /** 232 * Mark this query as the last query or operation in a transaction, after 233 * which the transaction should be committed. This should only be called 234 * for queries where root operation is a lookup. 235 */ setCommitIndicator()236 void setCommitIndicator() 237 { 238 assert(!getQueryDef().isScanQuery()); 239 m_commitIndicator = true; 240 } 241 242 /** 243 * Check if this is a pruned range scan. A range scan is pruned if the ranges 244 * are such that only a subset of the fragments need to be scanned for 245 * matching tuples. 246 * 247 * @param pruned This will be set to true if the operation is a pruned range 248 * scan. 249 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 250 */ 251 int isPrunable(bool& pruned); 252 253 /** Get the number of fragments to be read for the root operation.*/ getRootFragCount() const254 Uint32 getRootFragCount() const 255 { return m_rootFragCount; } 256 getResultStreamAlloc()257 NdbBulkAllocator& getResultStreamAlloc() 258 { return m_resultStreamAlloc; } 259 getTupleSetAlloc()260 NdbBulkAllocator& getTupleSetAlloc() 261 { return m_tupleSetAlloc; } 262 getRowBufferAlloc()263 NdbBulkAllocator& getRowBufferAlloc() 264 { return m_rowBufferAlloc; } 265 266 private: 267 /** Possible return values from NdbQueryImpl::awaitMoreResults. 268 * A subset of the integer values also matches those returned 269 * from PoolGuard::wait_scan(). 270 */ 271 enum FetchResult{ 272 FetchResult_gotError = -4, // There is an error avail in 'm_error.code' 273 FetchResult_sendFail = -3, 274 FetchResult_nodeFail = -2, 275 FetchResult_timeOut = -1, 276 FetchResult_ok = 0, 277 FetchResult_noMoreData = 1, 278 FetchResult_noMoreCache = 2 279 }; 280 281 /** 282 * Container of root fragments that the application is currently 283 * iterating over. 'Owned' by application thread and can be accesed 284 * without requiring a mutex lock. 285 * RootFragments are appended to a OrderedFragSet by ::prepareMoreResults() 286 * 287 */ 288 class OrderedFragSet{ 289 public: 290 // For calculating need for dynamically allocated memory. 291 static const Uint32 pointersPerFragment = 2; 292 293 explicit OrderedFragSet(); 294 295 ~OrderedFragSet(); 296 297 /** 298 * Prepare internal datastructures. 299 * param[in] allocator For allocating arrays of pointers. 300 * param[in] ordering Possible scan ordering. 301 * param[in] capacity Max no of root fragments. 302 * @return 0 if ok, else errorcode 303 */ 304 void prepare(NdbBulkAllocator& allocator, 305 NdbQueryOptions::ScanOrdering ordering, 306 int capacity, 307 const NdbRecord* keyRecord, 308 const NdbRecord* resultRecord); 309 310 /** 311 * Add root fragments with completed ResultSets to this OrderedFragSet. 312 * The PollGuard mutex must locked, and under its protection 313 * completed root fragments are 'consumed' from rootFrags[] and 314 * added to OrderedFragSet where it become available for the 315 * application thread. 316 */ 317 void prepareMoreResults(NdbRootFragment rootFrags[], Uint32 cnt); // Need mutex lock 318 319 /** Get the root fragment from which to read the next row.*/ 320 NdbRootFragment* getCurrent() const; 321 322 /** 323 * Re-organize the fragments after a row has been consumed. This is 324 * needed to remove fragments that has been emptied, and to re-sort 325 * fragments if doing a sorted scan. 326 */ 327 void reorganize(); 328 329 /** Reset object to an empty state.*/ 330 void clear(); 331 332 /** 333 * Get all fragments where more rows may be (pre-)fetched. 334 * (This method is not idempotent - the fragments are removed 335 * from the set.) 336 * @return Number of fragments (in &frags) from which more 337 * results should be requested. 338 */ 339 Uint32 getFetchMore(NdbRootFragment** &rootFrags); 340 341 private: 342 343 /** No of fragments to read until '::finalBatchReceived()'.*/ 344 int m_capacity; 345 /** Number of fragments in 'm_activeFrags'.*/ 346 int m_activeFragCount; 347 /** Number of fragments in 'm_fetchMoreFrags'. */ 348 int m_fetchMoreFragCount; 349 /** 350 * Number of fragments where the final batch has been received 351 * and consumed. 352 */ 353 int m_finalFragCount; 354 /** Ordering of index scan result.*/ 355 NdbQueryOptions::ScanOrdering m_ordering; 356 /** Needed for comparing records when ordering results.*/ 357 const NdbRecord* m_keyRecord; 358 /** Needed for comparing records when ordering results.*/ 359 const NdbRecord* m_resultRecord; 360 /** 361 * Fragments where some tuples in the current ResultSet has not 362 * yet been consumed. 363 */ 364 NdbRootFragment** m_activeFrags; 365 /** 366 * Fragments from which we should request more ResultSets. 367 * Either due to the current batch has been consumed, or double buffering 368 * of result sets allows us to request another batch before the current 369 * has been consumed. 370 */ 371 NdbRootFragment** m_fetchMoreFrags; 372 373 /** Add a complete fragment that has been received.*/ 374 void add(NdbRootFragment& frag); 375 376 /** For sorting fragment reads according to index value of first record. 377 * Also f1<f2 if f2 has reached end of data and f1 has not. 378 * @return 1 if f1>f2, 0 if f1==f2, -1 if f1<f2.*/ 379 int compare(const NdbRootFragment& frag1, 380 const NdbRootFragment& frag2) const; 381 382 /** For debugging purposes.*/ 383 bool verifySortOrder() const; 384 385 // No copying. 386 OrderedFragSet(const OrderedFragSet&); 387 OrderedFragSet& operator=(const OrderedFragSet&); 388 }; // class OrderedFragSet 389 390 /** The interface that is visible to the application developer.*/ 391 NdbQuery m_interface; 392 393 enum { // State of NdbQuery in API 394 Initial, // Constructed object, assiciated with a defined query 395 Defined, // Parameter values has been assigned 396 Prepared, // KeyInfo & AttrInfo prepared for execution 397 Executing, // Signal with exec. req. sent to TC 398 EndOfData, // All results rows consumed 399 Closed, // Query has been ::close()'ed 400 Failed, 401 Destructed 402 } m_state; 403 404 enum { // Assumed state of query cursor in TC block 405 Inactive, // Execution not started at TC 406 Active 407 } m_tcState; 408 409 /** Next query in same transaction.*/ 410 NdbQueryImpl* m_next; 411 /** Definition of this query.*/ 412 const NdbQueryDefImpl* m_queryDef; 413 414 /** Possible error status of this query.*/ 415 NdbError m_error; 416 417 /** 418 * Possible error received from TC / datanodes. 419 * Only access w/ PollGuard mutex as it is set by receiver thread. 420 * Checked and moved into 'm_error' with ::hasReceivedError(). 421 */ 422 int m_errorReceived; // BEWARE: protect with PollGuard mutex 423 424 /** Transaction in which this query instance executes.*/ 425 NdbTransaction& m_transaction; 426 427 /** Scan queries creates their own sub transaction which they 428 * execute within. 429 * Has same transId, Ndb*, ++ as the 'real' transaction above. 430 */ 431 NdbTransaction* m_scanTransaction; 432 433 /** The operations constituting this query.*/ 434 NdbQueryOperationImpl *m_operations; // 'Array of ' OperationImpls 435 Uint32 m_countOperations; // #elements in above array 436 437 /** Current global cursor position. Refers the current NdbQueryOperation which 438 * should be advanced to 'next' position for producing a new global set of results. 439 */ 440 Uint32 m_globalCursor; 441 442 /** Number of root fragments not yet completed within the current batch. 443 * Only access w/ PollGuard mutex as it is also updated by receiver thread 444 */ 445 Uint32 m_pendingFrags; // BEWARE: protect with PollGuard mutex 446 447 /** Number of fragments to be read by the root operation. (1 if root 448 * operation is a lookup)*/ 449 Uint32 m_rootFragCount; 450 451 /** 452 * This is an array with one element for each fragment that the root 453 * operation accesses (i.e. one for a lookup, all for a table scan). 454 * It keeps the state of the read operation on that fragment, and on 455 * any child operation instance derived from it. 456 */ 457 NdbRootFragment* m_rootFrags; 458 459 /** Root fragments that the application is currently iterating over. Only 460 * accessed by application thread. 461 */ 462 OrderedFragSet m_applFrags; 463 464 /** Number of root fragments for which confirmation for the final batch 465 * (with tcPtrI=RNIL) has been received. Observe that even if 466 * m_finalBatchFrags==m_rootFragCount, all tuples for the final batches may 467 * still not have been received (i.e. m_pendingFrags>0). 468 */ 469 Uint32 m_finalBatchFrags; // BEWARE: protect with PollGuard mutex 470 471 /** Number of IndexBounds set by API (index scans only) */ 472 Uint32 m_num_bounds; 473 474 /** 475 * Number of fields in the shortest bound (for an index scan root). 476 * Will be 0xffffffff if no bound has been set. 477 */ 478 Uint32 m_shortestBound; 479 480 /** 481 * Signal building section: 482 */ 483 Uint32Buffer m_attrInfo; // ATTRINFO: QueryTree + serialized parameters 484 Uint32Buffer m_keyInfo; // KEYINFO: Lookup key or scan bounds 485 486 /** True if this query starts a new transaction. */ 487 bool m_startIndicator; 488 489 /** True if the transaction should be committed after executing this query.*/ 490 bool m_commitIndicator; 491 492 /** This field tells if the root operation is a prunable range scan. A range 493 * scan is pruned if the ranges are such that only a subset of the fragments 494 * need to be scanned for matching tuples. (Currently, pushed scans can only 495 * be pruned if is there is a single range that maps to a single fragment. 496 */ 497 enum { 498 /** Call NdbQueryOperationDef::checkPrunable() to determine prunability.*/ 499 Prune_Unknown, 500 Prune_Yes, // The root is a prunable range scan. 501 Prune_No // The root is not a prunable range scan. 502 } m_prunability; 503 504 /** If m_prunability==Prune_Yes, this is the hash value of the single 505 * fragment that should be scanned.*/ 506 Uint32 m_pruneHashVal; 507 508 /** Allocator for NdbQueryOperationImpl objects.*/ 509 NdbBulkAllocator m_operationAlloc; 510 511 /** Allocator for NdbResultStream::TupleSet objects.*/ 512 NdbBulkAllocator m_tupleSetAlloc; 513 514 /** Allocator for NdbResultStream objects.*/ 515 NdbBulkAllocator m_resultStreamAlloc; 516 517 /** Allocator for pointers.*/ 518 NdbBulkAllocator m_pointerAlloc; 519 520 /** Allocator for result row buffers.*/ 521 NdbBulkAllocator m_rowBufferAlloc; 522 523 // Only constructable from factory ::buildQuery(); 524 explicit NdbQueryImpl( 525 NdbTransaction& trans, 526 const NdbQueryDefImpl& queryDef); 527 528 ~NdbQueryImpl(); 529 530 /** Release resources after scan has returned last available result */ 531 void postFetchRelease(); 532 533 /** Navigate to the next result from the root operation. */ 534 NdbQuery::NextResultOutcome nextRootResult(bool fetchAllowed, bool forceSend); 535 536 /** Send SCAN_NEXTREQ signal to fetch another batch from a scan query 537 * @return 0 if send succeeded, -1 otherwise. 538 */ 539 int sendFetchMore(NdbRootFragment* rootFrags[], Uint32 cnt, 540 bool forceSend); 541 542 /** Wait for more scan results which already has been REQuested to arrive. 543 * @return 0 if some rows did arrive, a negative value if there are errors 544 * (in m_error.code), 545 * and 1 of there are no more rows to receive. 546 */ 547 FetchResult awaitMoreResults(bool forceSend); 548 549 /** Check if we have received an error from TC, or datanodes. 550 * @return 'true' if an error is pending, 'false' otherwise. 551 */ 552 bool hasReceivedError(); // Need mutex lock 553 554 void setFetchTerminated(int aErrorCode, bool needClose); // Need mutex lock 555 556 /** Close cursor on TC */ 557 int closeTcCursor(bool forceSend); 558 559 /** Send SCAN_NEXTREQ(close) signal to close cursor on TC and datanodes. 560 * @return #signals sent, -1 if error. 561 */ 562 int sendClose(int nodeId); 563 getInterface() const564 const NdbQuery& getInterface() const 565 { return m_interface; } 566 getRoot() const567 NdbQueryOperationImpl& getRoot() const 568 { return getQueryOperation(0U); } 569 570 /** A complete batch has been received for a given root fragment 571 * Update whatever required before the appl. is allowed to navigate 572 * the result. 573 * @return: 'true' if its time to resume appl. threads 574 */ 575 bool handleBatchComplete(NdbRootFragment& rootFrag); 576 getPointerAlloc()577 NdbBulkAllocator& getPointerAlloc() 578 { return m_pointerAlloc; } 579 580 }; // class NdbQueryImpl 581 582 583 /** This class contains data members for NdbQueryOperation, such that these 584 * do not need to exposed in NdbQueryOperation.hpp. This class may be 585 * changed without forcing the customer to recompile his application. 586 */ 587 class NdbQueryOperationImpl { 588 589 /** For debugging.*/ 590 friend NdbOut& operator<<(NdbOut& out, const NdbQueryOperationImpl&); 591 592 friend class NdbQueryImpl; 593 594 public: 595 Uint32 getNoOfParentOperations() const; 596 NdbQueryOperationImpl& getParentOperation(Uint32 i) const; 597 NdbQueryOperationImpl* getParentOperation() const; 598 599 Uint32 getNoOfChildOperations() const; 600 NdbQueryOperationImpl& getChildOperation(Uint32 i) const; 601 602 /** A shorthand for getting the root operation. */ getRoot() const603 NdbQueryOperationImpl& getRoot() const 604 { return m_queryImpl.getRoot(); } 605 getQueryDef() const606 const NdbQueryDefImpl& getQueryDef() const 607 { return m_queryImpl.getQueryDef(); } 608 getQueryOperationDef() const609 const NdbQueryOperationDefImpl& getQueryOperationDef() const 610 { return m_operationDef; } 611 612 // Get the entire query object which this operation is part of getQuery() const613 NdbQueryImpl& getQuery() const 614 { return m_queryImpl; } 615 616 NdbRecAttr* getValue(const char* anAttrName, char* resultBuffer); 617 NdbRecAttr* getValue(Uint32 anAttrId, char* resultBuffer); 618 NdbRecAttr* getValue(const NdbColumnImpl&, char* resultBuffer); 619 620 int setResultRowBuf (const NdbRecord *rec, 621 char* resBuffer, 622 const unsigned char* result_mask); 623 624 int setResultRowRef (const NdbRecord* rec, 625 const char* & bufRef, 626 const unsigned char* result_mask); 627 628 NdbQuery::NextResultOutcome firstResult(); 629 630 NdbQuery::NextResultOutcome nextResult(bool fetchAllowed, bool forceSend); 631 632 bool isRowNULL() const; // Row associated with Operation is NULL value? 633 634 bool isRowChanged() const; // Prev ::nextResult() on NdbQuery retrieved a new 635 // value for this NdbQueryOperation 636 637 /** Process result data for this operation. Return true if batch complete.*/ 638 bool execTRANSID_AI(const Uint32* ptr, Uint32 len); 639 640 /** Process absence of result data for this operation. (Only used when the 641 * root operation is a lookup.) 642 * @return true if query complete.*/ 643 bool execTCKEYREF(const NdbApiSignal* aSignal); 644 645 /** Called once per complete (within batch) fragment when a SCAN_TABCONF 646 * signal is received. 647 * @param tcPtrI not in use. 648 * @param rowCount Number of rows for this fragment, including all rows from 649 * descendant lookup operations. 650 * @param receiver The receiver object that shall process the results.*/ 651 bool execSCAN_TABCONF(Uint32 tcPtrI, Uint32 rowCount, Uint32 nodeMask, 652 NdbReceiver* receiver); 653 getInterface() const654 const NdbQueryOperation& getInterface() const 655 { return m_interface; } getInterface()656 NdbQueryOperation& getInterface() 657 { return m_interface; } 658 659 /** Define result ordering for ordered index scan. It is an error to call 660 * this method on an operation that is not a scan, or to call it if an 661 * ordering was already set on the operation defintion by calling 662 * NdbQueryOperationDef::setOrdering(). 663 * @param ordering The desired ordering of results. 664 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 665 */ 666 int setOrdering(NdbQueryOptions::ScanOrdering ordering); 667 getOrdering() const668 NdbQueryOptions::ScanOrdering getOrdering() const 669 { return m_ordering; } 670 671 /** 672 * Set the number of fragments to be scanned in parallel. This only applies 673 * to table scans and non-sorted scans of ordered indexes. This method is 674 * only implemented for then root scan operation. 675 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 676 */ 677 int setParallelism(Uint32 parallelism); 678 679 /** 680 * Set the number of fragments to be scanned in parallel to the maximum 681 * possible value. This is the default for the root scan operation. 682 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 683 */ 684 int setMaxParallelism(); 685 686 /** 687 * Let the system dynamically choose the number of fragments to scan in 688 * parallel. The system will try to choose a value that gives optimal 689 * performance. This is the default for all scans but the root scan. This 690 * method only implemented for non-root scan operations. 691 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 692 */ 693 int setAdaptiveParallelism(); 694 695 /** Set the batch size (max rows per batch) for this operation. This 696 * only applies to scan operations, as lookup operations always will 697 * have the same batch size as its parent operation, or 1 if it is the 698 * root operation. 699 * @param batchSize Batch size (in number of rows). A value of 0 means 700 * use the default batch size. 701 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 702 */ 703 int setBatchSize(Uint32 batchSize); 704 705 /** 706 * Set the NdbInterpretedCode needed for defining a scan filter for 707 * this operation. 708 * It is an error to call this method on a lookup operation. 709 * @param code The interpreted code. This object is copied internally, 710 * meaning that 'code' may be destroyed as soon as this method returns. 711 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 712 */ 713 int setInterpretedCode(const NdbInterpretedCode& code); 714 bool hasInterpretedCode() const; 715 716 /** Verify magic number.*/ checkMagicNumber() const717 bool checkMagicNumber() const 718 { return m_magic == MAGIC; } 719 720 /** Get the maximal number of rows that may be returned in a single 721 * SCANREQ to the SPJ block. 722 */ getMaxBatchRows() const723 Uint32 getMaxBatchRows() const 724 { return m_maxBatchRows; } 725 726 /** Get size of row as required to buffer it. */ 727 Uint32 getRowSize() const; 728 getNdbRecord() const729 const NdbRecord* getNdbRecord() const 730 { return m_ndbRecord; } 731 732 private: 733 734 STATIC_CONST (MAGIC = 0xfade1234); 735 736 /** Interface for the application developer.*/ 737 NdbQueryOperation m_interface; 738 /** For verifying pointers to this class.*/ 739 const Uint32 m_magic; 740 /** NdbQuery to which this operation belongs. */ 741 NdbQueryImpl& m_queryImpl; 742 /** The (transaction independent ) definition from which this instance 743 * was created.*/ 744 const NdbQueryOperationDefImpl& m_operationDef; 745 746 /* MAYBE: replace m_children with navigation via m_operationDef.getChildOperation().*/ 747 /** Parent of this operation.*/ 748 NdbQueryOperationImpl* m_parent; 749 /** Children of this operation.*/ 750 Vector<NdbQueryOperationImpl*> m_children; 751 752 /** Max rows (per resultStream) in a scan batch.*/ 753 Uint32 m_maxBatchRows; 754 755 /** Buffer for parameters in serialized format */ 756 Uint32Buffer m_params; 757 758 /** User specified buffer for final storage of result.*/ 759 char* m_resultBuffer; 760 /** User specified pointer to application pointer that should be 761 * set to point to the current row inside a receiver buffer 762 * @see NdbQueryOperationImpl::setResultRowRef */ 763 const char** m_resultRef; 764 /** True if this operation gave no result for the current row.*/ 765 bool m_isRowNull; 766 767 /** Result record & optional bitmask to disable read of selected cols.*/ 768 const NdbRecord* m_ndbRecord; 769 const unsigned char* m_read_mask; 770 771 /** Head & tail of NdbRecAttr list defined by this operation. 772 * Used for old-style result retrieval (using getValue()).*/ 773 NdbRecAttr* m_firstRecAttr; 774 NdbRecAttr* m_lastRecAttr; 775 776 /** Ordering of scan results (only applies to ordered index scans.)*/ 777 NdbQueryOptions::ScanOrdering m_ordering; 778 779 /** A scan filter is mapped to an interpeter code program, which is stored 780 * here. (This field is NULL if no scan filter has been defined.)*/ 781 NdbInterpretedCode* m_interpretedCode; 782 783 /** True if this operation reads from any disk column. */ 784 bool m_diskInUserProjection; 785 786 /** Number of scan fragments to read in parallel. 787 */ 788 Uint32 m_parallelism; 789 790 /** Size of each result row (in bytes).*/ 791 mutable Uint32 m_rowSize; 792 793 explicit NdbQueryOperationImpl(NdbQueryImpl& queryImpl, 794 const NdbQueryOperationDefImpl& def); 795 ~NdbQueryOperationImpl(); 796 797 /** Copy NdbRecAttr and/or NdbRecord results from stream into appl. buffers */ 798 void fetchRow(NdbResultStream& resultStream); 799 800 /** Set result for this operation and all its descendand child 801 * operations to NULL. 802 */ 803 void nullifyResult(); 804 805 /** Release resources after scan has returned last available result */ 806 void postFetchRelease(); 807 808 /** Count number of descendant operations (excluding the operation itself) */ 809 Int32 getNoOfDescendantOperations() const; 810 811 /** 812 * Count number of leaf operations below/including self 813 */ 814 Uint32 getNoOfLeafOperations() const; 815 816 /** Serialize parameter values. 817 * @return possible error code.*/ 818 int serializeParams(const NdbQueryParamValue* paramValues); 819 820 int serializeProject(Uint32Buffer& attrInfo); 821 822 Uint32 calculateBatchedRows(const NdbQueryOperationImpl* closestScan); 823 void setBatchedRows(Uint32 batchedRows); 824 825 /** Prepare ATTRINFO for execution. (Add execution params++) 826 * @return possible error code.*/ 827 int prepareAttrInfo(Uint32Buffer& attrInfo); 828 829 /** 830 * Expand keys and bounds for the root operation into the KEYINFO section. 831 * @param keyInfo Actuall KEYINFO section the key / bounds are 832 * put into 833 * @param actualParam Instance values for NdbParamOperands. 834 * Returns: 0 if OK, or possible an errorcode. 835 */ 836 int prepareKeyInfo(Uint32Buffer& keyInfo, 837 const NdbQueryParamValue* actualParam); 838 839 int prepareLookupKeyInfo( 840 Uint32Buffer& keyInfo, 841 const NdbQueryOperandImpl* const keys[], 842 const NdbQueryParamValue* actualParam); 843 844 int prepareIndexKeyInfo( 845 Uint32Buffer& keyInfo, 846 const NdbQueryOperationDefImpl::IndexBound* bounds, 847 const NdbQueryParamValue* actualParam); 848 849 /** Return I-value (for putting in object map) for a receiver pointing back 850 * to this object. TCKEYCONF is processed by first looking up an 851 * NdbReceiver instance in the object map, and then following 852 * NdbReceiver::m_query_operation_impl here.*/ 853 Uint32 getIdOfReceiver() const; 854 855 /** 856 * If the operation has a scan filter, append the corresponding 857 * interpreter code to a buffer. 858 * @param attrInfo The buffer to which the code should be appended. 859 * @return possible error code */ 860 int prepareInterpretedCode(Uint32Buffer& attrInfo) const; 861 862 /** Returns true if this operation reads from any disk column. */ diskInUserProjection() const863 bool diskInUserProjection() const 864 { return m_diskInUserProjection; } 865 866 }; // class NdbQueryOperationImpl 867 868 869 #endif 870