1 /* 2 Copyright (c) 2011, 2021, Oracle and/or its affiliates. 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 /** 351 * Number of fragments where the final ResultSet has been received. 352 * (But not necessarily consumed!). 353 */ 354 int m_finalFragReceivedCount; 355 /** 356 * Number of fragments where the final ResultSet has been received 357 * and consumed. 358 */ 359 int m_finalFragConsumedCount; 360 361 /** Ordering of index scan result.*/ 362 NdbQueryOptions::ScanOrdering m_ordering; 363 /** Needed for comparing records when ordering results.*/ 364 const NdbRecord* m_keyRecord; 365 /** Needed for comparing records when ordering results.*/ 366 const NdbRecord* m_resultRecord; 367 /** 368 * Fragments where some tuples in the current ResultSet has not 369 * yet been consumed. 370 */ 371 NdbRootFragment** m_activeFrags; 372 /** 373 * Fragments from which we should request more ResultSets. 374 * Either due to the current ResultSets has been consumed, 375 * or double buffering of ResultSets allows us to request 376 * another batch before the current has been consumed. 377 */ 378 NdbRootFragment** m_fetchMoreFrags; 379 380 /** Add a complete fragment that has been received.*/ 381 void add(NdbRootFragment& frag); 382 383 /** For sorting fragment reads according to index value of first record. 384 * Also f1<f2 if f2 has reached end of data and f1 has not. 385 * @return 1 if f1>f2, 0 if f1==f2, -1 if f1<f2.*/ 386 int compare(const NdbRootFragment& frag1, 387 const NdbRootFragment& frag2) const; 388 389 /** For debugging purposes.*/ 390 bool verifySortOrder() const; 391 392 // No copying. 393 OrderedFragSet(const OrderedFragSet&); 394 OrderedFragSet& operator=(const OrderedFragSet&); 395 }; // class OrderedFragSet 396 397 /** The interface that is visible to the application developer.*/ 398 NdbQuery m_interface; 399 400 enum { // State of NdbQuery in API 401 Initial, // Constructed object, assiciated with a defined query 402 Defined, // Parameter values has been assigned 403 Prepared, // KeyInfo & AttrInfo prepared for execution 404 Executing, // Signal with exec. req. sent to TC 405 EndOfData, // All results rows consumed 406 Closed, // Query has been ::close()'ed 407 Failed, 408 Destructed 409 } m_state; 410 411 enum { // Assumed state of query cursor in TC block 412 Inactive, // Execution not started at TC 413 Active 414 } m_tcState; 415 416 /** Next query in same transaction.*/ 417 NdbQueryImpl* m_next; 418 /** Definition of this query.*/ 419 const NdbQueryDefImpl* m_queryDef; 420 421 /** Possible error status of this query.*/ 422 NdbError m_error; 423 424 /** 425 * Possible error received from TC / datanodes. 426 * Only access w/ PollGuard mutex as it is set by receiver thread. 427 * Checked and moved into 'm_error' with ::hasReceivedError(). 428 */ 429 int m_errorReceived; // BEWARE: protect with PollGuard mutex 430 431 /** Transaction in which this query instance executes.*/ 432 NdbTransaction& m_transaction; 433 434 /** Scan queries creates their own sub transaction which they 435 * execute within. 436 * Has same transId, Ndb*, ++ as the 'real' transaction above. 437 */ 438 NdbTransaction* m_scanTransaction; 439 440 /** The operations constituting this query.*/ 441 NdbQueryOperationImpl *m_operations; // 'Array of ' OperationImpls 442 Uint32 m_countOperations; // #elements in above array 443 444 /** Current global cursor position. Refers the current NdbQueryOperation which 445 * should be advanced to 'next' position for producing a new global set of results. 446 */ 447 Uint32 m_globalCursor; 448 449 /** Number of root fragments not yet completed within the current batch. 450 * Only access w/ PollGuard mutex as it is also updated by receiver thread 451 */ 452 Uint32 m_pendingFrags; // BEWARE: protect with PollGuard mutex 453 454 /** Number of fragments to be read by the root operation. (1 if root 455 * operation is a lookup)*/ 456 Uint32 m_rootFragCount; 457 458 /** 459 * This is an array with one element for each fragment that the root 460 * operation accesses (i.e. one for a lookup, all for a table scan). 461 * It keeps the state of the read operation on that fragment, and on 462 * any child operation instance derived from it. 463 */ 464 NdbRootFragment* m_rootFrags; 465 466 /** Root fragments that the application is currently iterating over. Only 467 * accessed by application thread. 468 */ 469 OrderedFragSet m_applFrags; 470 471 /** Number of root fragments for which confirmation for the final batch 472 * (with tcPtrI=RNIL) has been received. Observe that even if 473 * m_finalBatchFrags==m_rootFragCount, all tuples for the final batches may 474 * still not have been received (i.e. m_pendingFrags>0). 475 */ 476 Uint32 m_finalBatchFrags; // BEWARE: protect with PollGuard mutex 477 478 /** Number of IndexBounds set by API (index scans only) */ 479 Uint32 m_num_bounds; 480 481 /** 482 * Number of fields in the shortest bound (for an index scan root). 483 * Will be 0xffffffff if no bound has been set. 484 */ 485 Uint32 m_shortestBound; 486 487 /** 488 * Signal building section: 489 */ 490 Uint32Buffer m_attrInfo; // ATTRINFO: QueryTree + serialized parameters 491 Uint32Buffer m_keyInfo; // KEYINFO: Lookup key or scan bounds 492 493 /** True if this query starts a new transaction. */ 494 bool m_startIndicator; 495 496 /** True if the transaction should be committed after executing this query.*/ 497 bool m_commitIndicator; 498 499 /** This field tells if the root operation is a prunable range scan. A range 500 * scan is pruned if the ranges are such that only a subset of the fragments 501 * need to be scanned for matching tuples. (Currently, pushed scans can only 502 * be pruned if is there is a single range that maps to a single fragment. 503 */ 504 enum { 505 /** Call NdbQueryOperationDef::checkPrunable() to determine prunability.*/ 506 Prune_Unknown, 507 Prune_Yes, // The root is a prunable range scan. 508 Prune_No // The root is not a prunable range scan. 509 } m_prunability; 510 511 /** If m_prunability==Prune_Yes, this is the hash value of the single 512 * fragment that should be scanned.*/ 513 Uint32 m_pruneHashVal; 514 515 /** Allocator for NdbQueryOperationImpl objects.*/ 516 NdbBulkAllocator m_operationAlloc; 517 518 /** Allocator for NdbResultStream::TupleSet objects.*/ 519 NdbBulkAllocator m_tupleSetAlloc; 520 521 /** Allocator for NdbResultStream objects.*/ 522 NdbBulkAllocator m_resultStreamAlloc; 523 524 /** Allocator for pointers.*/ 525 NdbBulkAllocator m_pointerAlloc; 526 527 /** Allocator for result row buffers.*/ 528 NdbBulkAllocator m_rowBufferAlloc; 529 530 // Only constructable from factory ::buildQuery(); 531 explicit NdbQueryImpl( 532 NdbTransaction& trans, 533 const NdbQueryDefImpl& queryDef); 534 535 ~NdbQueryImpl(); 536 537 /** Release resources after scan has returned last available result */ 538 void postFetchRelease(); 539 540 /** Navigate to the next result from the root operation. */ 541 NdbQuery::NextResultOutcome nextRootResult(bool fetchAllowed, bool forceSend); 542 543 /** Send SCAN_NEXTREQ signal to fetch another batch from a scan query 544 * @return 0 if send succeeded, -1 otherwise. 545 */ 546 int sendFetchMore(NdbRootFragment* rootFrags[], Uint32 cnt, 547 bool forceSend); 548 549 /** Wait for more scan results which already has been REQuested to arrive. 550 * @return 0 if some rows did arrive, a negative value if there are errors 551 * (in m_error.code), 552 * and 1 of there are no more rows to receive. 553 */ 554 FetchResult awaitMoreResults(bool forceSend); 555 556 /** Check if we have received an error from TC, or datanodes. 557 * @return 'true' if an error is pending, 'false' otherwise. 558 */ 559 bool hasReceivedError(); // Need mutex lock 560 561 void setFetchTerminated(int aErrorCode, bool needClose); // Need mutex lock 562 563 /** Close cursor on TC */ 564 int closeTcCursor(bool forceSend); 565 566 /** Send SCAN_NEXTREQ(close) signal to close cursor on TC and datanodes. 567 * @return #signals sent, -1 if error. 568 */ 569 int sendClose(int nodeId); 570 getInterface() const571 const NdbQuery& getInterface() const 572 { return m_interface; } 573 getRoot() const574 NdbQueryOperationImpl& getRoot() const 575 { return getQueryOperation(0U); } 576 577 /** A complete batch has been received for a given root fragment 578 * Update whatever required before the appl. is allowed to navigate 579 * the result. 580 * @return: 'true' if its time to resume appl. threads 581 */ 582 bool handleBatchComplete(NdbRootFragment& rootFrag); 583 getPointerAlloc()584 NdbBulkAllocator& getPointerAlloc() 585 { return m_pointerAlloc; } 586 587 }; // class NdbQueryImpl 588 589 590 /** This class contains data members for NdbQueryOperation, such that these 591 * do not need to exposed in NdbQueryOperation.hpp. This class may be 592 * changed without forcing the customer to recompile his application. 593 */ 594 class NdbQueryOperationImpl { 595 596 /** For debugging.*/ 597 friend NdbOut& operator<<(NdbOut& out, const NdbQueryOperationImpl&); 598 599 friend class NdbQueryImpl; 600 601 public: 602 Uint32 getNoOfParentOperations() const; 603 NdbQueryOperationImpl& getParentOperation(Uint32 i) const; 604 NdbQueryOperationImpl* getParentOperation() const; 605 606 Uint32 getNoOfChildOperations() const; 607 NdbQueryOperationImpl& getChildOperation(Uint32 i) const; 608 609 /** A shorthand for getting the root operation. */ getRoot() const610 NdbQueryOperationImpl& getRoot() const 611 { return m_queryImpl.getRoot(); } 612 613 // A shorthand method. getInternalOpNo() const614 Uint32 getInternalOpNo() const 615 { 616 return m_operationDef.getInternalOpNo(); 617 } 618 getQueryDef() const619 const NdbQueryDefImpl& getQueryDef() const 620 { return m_queryImpl.getQueryDef(); } 621 getQueryOperationDef() const622 const NdbQueryOperationDefImpl& getQueryOperationDef() const 623 { return m_operationDef; } 624 625 // Get the entire query object which this operation is part of getQuery() const626 NdbQueryImpl& getQuery() const 627 { return m_queryImpl; } 628 629 NdbRecAttr* getValue(const char* anAttrName, char* resultBuffer); 630 NdbRecAttr* getValue(Uint32 anAttrId, char* resultBuffer); 631 NdbRecAttr* getValue(const NdbColumnImpl&, char* resultBuffer); 632 633 int setResultRowBuf (const NdbRecord *rec, 634 char* resBuffer, 635 const unsigned char* result_mask); 636 637 int setResultRowRef (const NdbRecord* rec, 638 const char* & bufRef, 639 const unsigned char* result_mask); 640 641 NdbQuery::NextResultOutcome firstResult(); 642 643 NdbQuery::NextResultOutcome nextResult(bool fetchAllowed, bool forceSend); 644 645 bool isRowNULL() const; // Row associated with Operation is NULL value? 646 647 bool isRowChanged() const; // Prev ::nextResult() on NdbQuery retrieved a new 648 // value for this NdbQueryOperation 649 650 /** Process result data for this operation. Return true if batch complete.*/ 651 bool execTRANSID_AI(const Uint32* ptr, Uint32 len); 652 653 /** Process absence of result data for this operation. (Only used when the 654 * root operation is a lookup.) 655 * @return true if query complete.*/ 656 bool execTCKEYREF(const NdbApiSignal* aSignal); 657 658 /** Called once per complete (within batch) fragment when a SCAN_TABCONF 659 * signal is received. 660 * @param tcPtrI not in use. 661 * @param rowCount Number of rows for this fragment, including all rows from 662 * descendant lookup operations. 663 * @param receiver The receiver object that shall process the results.*/ 664 bool execSCAN_TABCONF(Uint32 tcPtrI, Uint32 rowCount, Uint32 nodeMask, 665 NdbReceiver* receiver); 666 getInterface() const667 const NdbQueryOperation& getInterface() const 668 { return m_interface; } getInterface()669 NdbQueryOperation& getInterface() 670 { return m_interface; } 671 672 /** Define result ordering for ordered index scan. It is an error to call 673 * this method on an operation that is not a scan, or to call it if an 674 * ordering was already set on the operation defintion by calling 675 * NdbQueryOperationDef::setOrdering(). 676 * @param ordering The desired ordering of results. 677 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 678 */ 679 int setOrdering(NdbQueryOptions::ScanOrdering ordering); 680 getOrdering() const681 NdbQueryOptions::ScanOrdering getOrdering() const 682 { return m_ordering; } 683 684 /** 685 * Set the number of fragments to be scanned in parallel. This only applies 686 * to table scans and non-sorted scans of ordered indexes. This method is 687 * only implemented for then root scan operation. 688 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 689 */ 690 int setParallelism(Uint32 parallelism); 691 692 /** 693 * Set the number of fragments to be scanned in parallel to the maximum 694 * possible value. This is the default for the root scan operation. 695 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 696 */ 697 int setMaxParallelism(); 698 699 /** 700 * Let the system dynamically choose the number of fragments to scan in 701 * parallel. The system will try to choose a value that gives optimal 702 * performance. This is the default for all scans but the root scan. This 703 * method only implemented for non-root scan operations. 704 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 705 */ 706 int setAdaptiveParallelism(); 707 708 /** Set the batch size (max rows per batch) for this operation. This 709 * only applies to scan operations, as lookup operations always will 710 * have the same batch size as its parent operation, or 1 if it is the 711 * root operation. 712 * @param batchSize Batch size (in number of rows). A value of 0 means 713 * use the default batch size. 714 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 715 */ 716 int setBatchSize(Uint32 batchSize); 717 718 /** 719 * Set the NdbInterpretedCode needed for defining a scan filter for 720 * this operation. 721 * It is an error to call this method on a lookup operation. 722 * @param code The interpreted code. This object is copied internally, 723 * meaning that 'code' may be destroyed as soon as this method returns. 724 * @return 0 if ok, -1 in case of error (call getNdbError() for details.) 725 */ 726 int setInterpretedCode(const NdbInterpretedCode& code); 727 bool hasInterpretedCode() const; 728 729 /** Verify magic number.*/ checkMagicNumber() const730 bool checkMagicNumber() const 731 { return m_magic == MAGIC; } 732 733 /** Get the maximal number of rows that may be returned in a single 734 * SCANREQ to the SPJ block. 735 */ getMaxBatchRows() const736 Uint32 getMaxBatchRows() const 737 { return m_maxBatchRows; } 738 739 /** Get size of buffer required to hold a full batch of 'packed' rows */ 740 Uint32 getBatchBufferSize() const; 741 742 /** Get size of a full row. */ 743 Uint32 getRowSize() const; 744 getNdbRecord() const745 const NdbRecord* getNdbRecord() const 746 { return m_ndbRecord; } 747 748 private: 749 750 STATIC_CONST (MAGIC = 0xfade1234); 751 752 /** Interface for the application developer.*/ 753 NdbQueryOperation m_interface; 754 /** For verifying pointers to this class.*/ 755 const Uint32 m_magic; 756 /** NdbQuery to which this operation belongs. */ 757 NdbQueryImpl& m_queryImpl; 758 /** The (transaction independent ) definition from which this instance 759 * was created.*/ 760 const NdbQueryOperationDefImpl& m_operationDef; 761 762 /* MAYBE: replace m_children with navigation via m_operationDef.getChildOperation().*/ 763 /** Parent of this operation.*/ 764 NdbQueryOperationImpl* m_parent; 765 /** Children of this operation.*/ 766 Vector<NdbQueryOperationImpl*> m_children; 767 768 /** Max rows (per resultStream) in a scan batch.*/ 769 Uint32 m_maxBatchRows; 770 771 /** Buffer for parameters in serialized format */ 772 Uint32Buffer m_params; 773 774 /** User specified buffer for final storage of result.*/ 775 char* m_resultBuffer; 776 /** User specified pointer to application pointer that should be 777 * set to point to the current row inside a receiver buffer 778 * @see NdbQueryOperationImpl::setResultRowRef */ 779 const char** m_resultRef; 780 /** True if this operation gave no result for the current row.*/ 781 bool m_isRowNull; 782 783 /** Result record & optional bitmask to disable read of selected cols.*/ 784 const NdbRecord* m_ndbRecord; 785 const unsigned char* m_read_mask; 786 787 /** Head & tail of NdbRecAttr list defined by this operation. 788 * Used for old-style result retrieval (using getValue()).*/ 789 NdbRecAttr* m_firstRecAttr; 790 NdbRecAttr* m_lastRecAttr; 791 792 /** Ordering of scan results (only applies to ordered index scans.)*/ 793 NdbQueryOptions::ScanOrdering m_ordering; 794 795 /** A scan filter is mapped to an interpeter code program, which is stored 796 * here. (This field is NULL if no scan filter has been defined.)*/ 797 NdbInterpretedCode* m_interpretedCode; 798 799 /** True if this operation reads from any disk column. */ 800 bool m_diskInUserProjection; 801 802 /** Number of scan fragments to read in parallel. 803 */ 804 Uint32 m_parallelism; 805 806 /** Size of each unpacked result row (in bytes).*/ 807 mutable Uint32 m_rowSize; 808 809 /** Size of the buffer required to hold a batch of result rows */ 810 mutable Uint32 m_batchBufferSize; 811 812 explicit NdbQueryOperationImpl(NdbQueryImpl& queryImpl, 813 const NdbQueryOperationDefImpl& def); 814 ~NdbQueryOperationImpl(); 815 816 /** Copy NdbRecAttr and/or NdbRecord results from stream into appl. buffers */ 817 void fetchRow(NdbResultStream& resultStream); 818 819 /** Set result for this operation and all its descendand child 820 * operations to NULL. 821 */ 822 void nullifyResult(); 823 824 /** Release resources after scan has returned last available result */ 825 void postFetchRelease(); 826 827 /** Count number of descendant operations (excluding the operation itself) */ 828 Int32 getNoOfDescendantOperations() const; 829 830 /** 831 * Count number of leaf operations below/including self 832 */ 833 Uint32 getNoOfLeafOperations() const; 834 835 /** Serialize parameter values. 836 * @return possible error code.*/ 837 int serializeParams(const NdbQueryParamValue* paramValues); 838 839 int serializeProject(Uint32Buffer& attrInfo); 840 841 Uint32 calculateBatchedRows(const NdbQueryOperationImpl* closestScan); 842 void setBatchedRows(Uint32 batchedRows); 843 844 /** Prepare ATTRINFO for execution. (Add execution params++) 845 * @return possible error code.*/ 846 int prepareAttrInfo(Uint32Buffer& attrInfo); 847 848 /** 849 * Expand keys and bounds for the root operation into the KEYINFO section. 850 * @param keyInfo Actuall KEYINFO section the key / bounds are 851 * put into 852 * @param actualParam Instance values for NdbParamOperands. 853 * Returns: 0 if OK, or possible an errorcode. 854 */ 855 int prepareKeyInfo(Uint32Buffer& keyInfo, 856 const NdbQueryParamValue* actualParam); 857 858 int prepareLookupKeyInfo( 859 Uint32Buffer& keyInfo, 860 const NdbQueryOperandImpl* const keys[], 861 const NdbQueryParamValue* actualParam); 862 863 int prepareIndexKeyInfo( 864 Uint32Buffer& keyInfo, 865 const NdbQueryOperationDefImpl::IndexBound* bounds, 866 const NdbQueryParamValue* actualParam); 867 868 /** Return I-value (for putting in object map) for a receiver pointing back 869 * to this object. TCKEYCONF is processed by first looking up an 870 * NdbReceiver instance in the object map, and then following 871 * NdbReceiver::m_query_operation_impl here.*/ 872 Uint32 getIdOfReceiver() const; 873 874 /** 875 * If the operation has a scan filter, append the corresponding 876 * interpreter code to a buffer. 877 * @param attrInfo The buffer to which the code should be appended. 878 * @return possible error code */ 879 int prepareInterpretedCode(Uint32Buffer& attrInfo) const; 880 881 /** Returns true if this operation reads from any disk column. */ diskInUserProjection() const882 bool diskInUserProjection() const 883 { return m_diskInUserProjection; } 884 885 }; // class NdbQueryOperationImpl 886 887 888 #endif 889