List:Commits« Previous MessageNext Message »
From:Jan Wedvik Date:July 15 2010 6:14pm
Subject:bzr push into mysql-5.1-telco-7.0-spj-scan-vs-scan branch (jan.wedvik:3206
to 3211)
View as plain text  
 3211 Jan Wedvik	2010-07-15
      Added more comments.

    modified:
      storage/ndb/src/ndbapi/NdbQueryBuilder.cpp
      storage/ndb/src/ndbapi/NdbQueryOperation.cpp
 3210 Jan Wedvik	2010-07-15
      Removed m_newRow.

    modified:
      storage/ndb/src/ndbapi/NdbQueryOperation.cpp
 3209 Jan Wedvik	2010-07-15
      Renamed literals.

    modified:
      storage/ndb/src/ndbapi/NdbQueryOperation.cpp
 3208 Jan Wedvik	2010-07-15
      Introduced m_currentRow.

    modified:
      storage/ndb/src/ndbapi/NdbQueryOperation.cpp
 3207 Jan Wedvik	2010-07-15
      With local newRow.

    modified:
      storage/ndb/src/ndbapi/NdbQueryOperation.cpp
 3206 Jan Wedvik	2010-07-15 [merge]
      Before making newRow local.

    modified:
      storage/ndb/src/ndbapi/NdbQueryBuilder.cpp
      storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp
      storage/ndb/src/ndbapi/NdbQueryOperation.cpp
      storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp
      storage/ndb/src/ndbapi/NdbReceiver.cpp
=== modified file 'storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp	2010-06-22 05:24:36 +0000
+++ b/storage/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp	2010-07-14 12:45:09 +0000
@@ -10234,7 +10234,21 @@ Dblqh::copyNextRange(Uint32 * dst, TcCon
     const Uint32 rangeLen= (firstWord >> 16) ? (firstWord >> 16) : totalLen;
     tcPtrP->m_scan_curr_range_no= (firstWord & 0xFFF0) >> 4;
     tcPtrP->m_anyValue = ((firstWord & 0xFFF0) >> 4) << 16;
-    
+    /**
+     * When running linked operations (i.e via the SPJ block) the API reqiures 
+     * the combination of tuple id and root fragment id to be unique for each 
+     * tuple in order to associate result tuples from parent and child 
+     * operations. If there is a non-root scan, then each SPJ block will
+     * scan each fragment. The node id is therefore included in the tuple
+     * id, to make sure that tuple ids from scans initiated by the same SPJ
+     * block on different fragments are distinct. (Note that all fragment
+     * scans initiated by the same SPJ block will have the same root fragment 
+     * id.)
+     * FIXME: The code below will break if there are more than 255 tuples in a 
+     * batch or more than 255 data nodes.
+     */
+    ndbassert(getOwnNodeId() < 0x100);
+    tcPtrP->m_anyValue |= getOwnNodeId() << 8;
     firstWord &= 0xF; // Remove length+range num from first word
     
     /* Write range info to dst */

=== modified file 'storage/ndb/src/ndbapi/NdbQueryBuilder.cpp'
--- a/storage/ndb/src/ndbapi/NdbQueryBuilder.cpp	2010-07-14 20:14:01 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryBuilder.cpp	2010-07-15 17:51:57 +0000
@@ -1609,6 +1609,7 @@ NdbQueryOperationDefImpl::NdbQueryOperat
                                      Uint32      ix)
   :m_isPrepared(false), 
    m_diskInChildProjection(false), 
+   m_hasScanDescendant(false),
    m_table(table), 
    m_ident(ident), 
    m_ix(ix), m_id(ix),
@@ -1720,6 +1721,18 @@ NdbQueryOperationDefImpl::addColumnRef(c
   return spjRef;
 }
 
+void NdbQueryOperationDefImpl::markScanAncestors()
+{
+  NdbQueryOperationDefImpl* operation = this;
+  do
+  {
+    // FIXME: Set an error code instead.
+    assert(!operation->m_hasScanDescendant);
+    operation->m_hasScanDescendant = true;
+    operation = operation->getParentOperation();
+  }
+  while (operation != NULL && !operation->isScanOperation());
+}
 
 /** This class is used for serializing sequences of 16 bit integers,
  * where the first 16 bit integer specifies the length of the sequence.
@@ -2229,6 +2242,16 @@ NdbQueryIndexOperationDefImpl
 } // NdbQueryIndexOperationDefImpl::serializeOperation
 
 
+NdbQueryScanOperationDefImpl::NdbQueryScanOperationDefImpl (
+                           const NdbTableImpl& table,
+                           const NdbQueryOptionsImpl& options,
+                           const char* ident,
+                           Uint32      ix)
+  : NdbQueryOperationDefImpl(table,options,ident,ix)
+{
+  markScanAncestors();
+}
+
 int
 NdbQueryScanOperationDefImpl::serialize(Uint32Buffer& serializedDef,
                                         const NdbTableImpl& tableOrIndex)

=== modified file 'storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp	2010-07-14 20:14:01 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp	2010-07-15 14:14:24 +0000
@@ -285,18 +285,19 @@ public:
   Uint32 getNoOfParentOperations() const
   { return (m_parent) ? 1 : 0; }
 
-  const NdbQueryOperationDefImpl& getParentOperation(Uint32 i) const
+  NdbQueryOperationDefImpl& getParentOperation(Uint32 i) const
   { assert(i==0 && m_parent!=NULL);
     return *m_parent;
   }
-  const NdbQueryOperationDefImpl* getParentOperation() const
+
+  NdbQueryOperationDefImpl* getParentOperation() const
   { return m_parent;
   }
 
   Uint32 getNoOfChildOperations() const
   { return m_children.size(); }
 
-  const NdbQueryOperationDefImpl& getChildOperation(Uint32 i) const
+  NdbQueryOperationDefImpl& getChildOperation(Uint32 i) const
   { return *m_children[i]; }
 
   const NdbTableImpl& getTable() const
@@ -349,6 +350,13 @@ public:
   // Return 'true' is query type is a multi-row scan
   virtual bool isScanOperation() const = 0;
 
+  /** Return true if this operation or any of its descendants is a scan.*/
+  bool hasScanDescendant() const
+  { return m_hasScanDescendant; }
+
+  /** Mark this operation and all its ancestors as having a scan decendant.*/
+  void markScanAncestors();
+
   virtual const NdbQueryOperationDef& getInterface() const = 0; 
 
   /** Make a serialized representation of this operation, corresponding to
@@ -409,6 +417,9 @@ protected:
    */
   bool m_diskInChildProjection;
 
+  /** True if this operation or any of its descendants is a scan.*/
+  bool m_hasScanDescendant;
+
 private:
   bool isChildOf(const NdbQueryOperationDefImpl* parentOp) const;
 
@@ -452,9 +463,7 @@ public:
                            const NdbTableImpl& table,
                            const NdbQueryOptionsImpl& options,
                            const char* ident,
-                           Uint32      ix)
-  : NdbQueryOperationDefImpl(table,options,ident,ix)
-  {}
+                           Uint32      ix);
 
   virtual bool isScanOperation() const
   { return true; }

=== modified file 'storage/ndb/src/ndbapi/NdbQueryOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbQueryOperation.cpp	2010-07-14 22:09:14 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryOperation.cpp	2010-07-15 17:51:57 +0000
@@ -135,16 +135,13 @@ class NdbRootFragment {
 public:
   explicit NdbRootFragment();
 
-  ~NdbRootFragment()
-  { delete[] m_tupleIdx; }
-
   /**
    * Initialize object.
    * @param query Enclosing query.
    * @param fragNo This object manages state for reading from the fragNo'th 
    * fragment that the root operation accesses.
    */
-  Uint32 init(NdbQueryImpl& query, Uint32 fragNo); 
+  void init(NdbQueryImpl& query, Uint32 fragNo); 
 
   Uint32 getFragNo() const
   { return m_fragNo; }
@@ -202,10 +199,6 @@ public:
    */
   bool isEmpty() const;
 
-  void buildResultIndex();
-
-  bool fetchScanResults();
-
 private:
   STATIC_CONST( voidFragNo = 0xffffffff);
 
@@ -232,11 +225,6 @@ private:
    * Each element is true iff a SCAN_TABCONF (for that fragment) or 
    * TCKEYCONF message has been received */
   bool m_confReceived;
-
-  Uint32 m_currentTuple;
-
-  Uint16 *m_tupleIdx;
-
 }; //NdbRootFragment
 
 
@@ -251,7 +239,23 @@ private:
  * structures for correlating child and parent tuples.
  */
 class NdbResultStream {
+  friend bool NdbRootFragment::isEmpty() const;
 public:
+
+  /** Outcome when asking for a new now from a scan.*/
+  enum ScanRowResult
+  {
+    /** Undefined value, for variable initialization etc..*/
+    ScanRowResult_void,
+    /** There was a new row.*/
+    ScanRowResult_gotRow,
+    /** There are no more rows.*/
+    ScanRowResult_endOfScan,
+    /** There are no more rows in the current batch, but there may be more 
+     * in subsequent batches.*/
+    ScanRowResult_endOfBatch
+  };
+
   /**
    * @param operation The operation for which we will receive results.
    * @param rootFragNo 0..n-1 when the root operation reads from n fragments.
@@ -299,19 +303,17 @@ public:
    */ 
   void handleBatchComplete();
 
+  /**
+   * Get the next row for an operation that is either a scan itself or a 
+   * descendant of a scan.
+   * @param parentId Tuple id of parent tuple (or tupleNotFound if this is the
+   * root operation.
+   */
+  ScanRowResult getNextScanRow(Uint16 parentId);
+
   /** For debugging.*/
   friend NdbOut& operator<<(NdbOut& out, const NdbResultStream&);
 
-  Uint16 getParentId(Uint16 tupleNo) const
-  { return m_tupleSet[tupleNo].m_parentId; }
-
-  Uint16 getTupleId(Uint16 tupleNo) const
-  { return m_tupleSet[tupleNo].m_tupleId; }
-
-  Uint16 findTupleWithParentId(Uint16 parentId) const;
-
-  Uint16 findTupleWithId(Uint16 tupleId) const;
-
 private:
   /** This stream handles results derived from the m_rootFragNo'th 
    * fragment of the root operation.*/
@@ -329,6 +331,27 @@ private:
   /** Operation to which this resultStream belong.*/
   NdbQueryOperationImpl& m_operation;
 
+  /** This is the state of the iterator used by getNextScanRow().*/
+  enum
+  {
+    /** The first row has not been fetched yet.*/
+    Iter_notStarted,
+    /** Get next row from child operation, and keep the current tuple for 
+     * this operation..*/
+    Iter_stepChild,
+    /** Get next row from this operation.*/
+    Iter_stepSelf,
+    /** Last row for current batch has been returned.*/
+    Iter_finished
+  } m_iterState;
+
+  /** This is the tuple id of the current parent tuple (when iterating using 
+   * getNextScanRow())*/
+  Uint16 m_currentParentId;
+  
+  /** This is the current row number (when iterating using getNextScanRow())*/
+  Uint16 m_currentRow; // FIXME: Use NdbReciver::m_current_row instead???
+
   /**
    * TupleSet contain two logically distinct set of information:
    *
@@ -339,9 +362,9 @@ private:
    *
    *  - A HashMap on 'm_parentId' used to locate tuples correlated
    *    to a parent tuple. Indexes by hashing the parentId such that:
-   *     - [hash(parentId)].m_parentHashHead will then index the first
+   *     - [hash(parentId)].m_hash_head will then index the first
    *       TupleSet entry potential containing the parentId to locate.
-   *     - .m_parentHashNext in the indexed TupleSet may index the next TupleSet 
+   *     - .m_hash_next in the indexed TupleSet may index the next TupleSet 
    *       to considder.
    *       
    * Both the child/parent correlation set and the parentId HashMap has been
@@ -357,12 +380,8 @@ private:
     Uint16 m_parentId;  // Id of parent tuple which this tuple is correlated with
     Uint16 m_tupleId;   // Id of this tuple
 
-    Uint16 m_hashHead; // Index of first item in TupleSet[] matching a parentId.
-
-    Uint16 m_hashNext; // 'next' index matching 
-
-    Uint16 m_parentHashHead; // Index of first item in TupleSet[] matching a hashed parentId.
-    Uint16 m_parentHashNext; // 'next' index matching 
+    Uint16 m_hash_head; // Index of first item in TupleSet[] matching a hashed parentId.
+    Uint16 m_hash_next; // 'next' index matching 
 
     explicit TupleSet()
     {}
@@ -381,6 +400,13 @@ private:
                          Uint16 tupleId, 
                          Uint16 tupleNo);
 
+  Uint16 getTupleId(Uint16 tupleNo) const
+  { return m_tupleSet[tupleNo].m_tupleId; }
+
+  Uint16 findTupleWithParentId(Uint16 parentId);
+
+  Uint16 findNextTuple();
+
   /** No copying.*/
   NdbResultStream(const NdbResultStream&);
   NdbResultStream& operator=(const NdbResultStream&);
@@ -396,6 +422,9 @@ NdbResultStream::NdbResultStream(NdbQuer
   m_maxRows(0),
   m_rowCount(0),
   m_operation(operation),
+  m_iterState(Iter_notStarted),
+  m_currentParentId(tupleNotFound),
+  m_currentRow(tupleNotFound),
   m_tupleSet(NULL)
 {};
 
@@ -449,8 +478,7 @@ NdbResultStream::clearParentChildMap()
   {
     m_tupleSet[i].m_parentId = tupleNotFound;
     m_tupleSet[i].m_tupleId  = tupleNotFound;
-    m_tupleSet[i].m_hashHead = m_maxRows;
-    m_tupleSet[i].m_parentHashHead = m_maxRows;
+    m_tupleSet[i].m_hash_head = tupleNotFound;
   }
 }
 
@@ -460,55 +488,56 @@ NdbResultStream::setParentChildMap(Uint1
                                    Uint16 tupleNo)
 {
   assert (m_operation.getQueryDef().isScanQuery());
+  assert (tupleNo < m_maxRows);
+  for (Uint32 i = 0; i < tupleNo; i++)
+  {
+    // Check that tuple id is unique.
+    assert (m_tupleSet[i].m_tupleId != tupleId); 
+  }
   m_tupleSet[tupleNo].m_parentId = parentId;
   m_tupleSet[tupleNo].m_tupleId  = tupleId;
 
-  /* Insert tupleId in HashMap */
-  const Uint16 hash = (tupleId % m_maxRows);
-  m_tupleSet[tupleNo].m_hashNext = 
-    m_tupleSet[hash].m_hashHead;
-  m_tupleSet[hash].m_hashHead  = tupleNo;
-
   /* Insert parentId in HashMap */
   if (parentId != tupleNotFound)
   {
-    const Uint16 parentHash = (parentId % m_maxRows);
-    m_tupleSet[tupleNo].m_parentHashNext = 
-      m_tupleSet[parentHash].m_parentHashHead;
-    m_tupleSet[parentHash].m_parentHashHead  = tupleNo;
+    const Uint16 hash = (parentId % m_maxRows);
+    m_tupleSet[tupleNo].m_hash_next = m_tupleSet[hash].m_hash_head;
+    m_tupleSet[hash].m_hash_head  = tupleNo;
   }
 }
 
 Uint16
-NdbResultStream::findTupleWithParentId(Uint16 parentId) const
+NdbResultStream::findTupleWithParentId(Uint16 parentId)
 {
   assert (m_operation.getQueryDef().isScanQuery());
+  m_currentParentId = parentId;
 
   const Uint16 hash = (parentId % m_maxRows);
-  Uint16 tupleIx = m_tupleSet[hash].m_parentHashHead;
-  while (tupleIx < m_maxRows)
+  m_currentRow = m_tupleSet[hash].m_hash_head;
+  while (m_currentRow != tupleNotFound)
   {
-    if (m_tupleSet[tupleIx].m_parentId == parentId)
-      return tupleIx;
+    assert(m_currentRow < m_maxRows);
+    if (m_tupleSet[m_currentRow].m_parentId == parentId)
+      return m_currentRow;
 
-    tupleIx = m_tupleSet[tupleIx].m_parentHashNext;
+    m_currentRow = m_tupleSet[m_currentRow].m_hash_next;
   }
   return tupleNotFound;
 }
 
 Uint16
-NdbResultStream::findTupleWithId(Uint16 tupleId) const
+NdbResultStream::findNextTuple()
 {
   assert (m_operation.getQueryDef().isScanQuery());
 
-  const Uint16 hash = (tupleId % m_maxRows);
-  Uint16 tupleIx = m_tupleSet[hash].m_hashHead;
-  while (tupleIx < m_maxRows)
+  while (m_currentRow != tupleNotFound)
   {
-    if (m_tupleSet[tupleIx].m_tupleId == tupleId)
-      return tupleIx;
+    assert(m_currentRow < m_maxRows);
+    m_currentRow = m_tupleSet[m_currentRow].m_hash_next;
 
-    tupleIx = m_tupleSet[tupleIx].m_hashNext;
+    if (m_currentRow != tupleNotFound &&
+        m_tupleSet[m_currentRow].m_parentId == m_currentParentId)
+      return m_currentRow;
   }
   return tupleNotFound;
 }
@@ -553,6 +582,160 @@ NdbResultStream::handleBatchComplete()
   getReceiver().m_result_rows = getRowCount();
 }
 
+NdbResultStream::ScanRowResult
+NdbResultStream::getNextScanRow(Uint16 parentId)
+{
+  const bool isRoot = 
+    m_operation.getQueryOperationDef().getQueryOperationIx() == 0;
+
+  /* Restart iteration if parent id has changed.*/
+  if (!isRoot && m_currentParentId != parentId)
+  {
+    assert (parentId != tupleNotFound);
+    m_currentParentId = parentId;
+    m_iterState = Iter_notStarted;
+  }        
+  assert(m_iterState != Iter_finished);
+
+  /* Loop until we either find a suitable set of rows for this operation
+   * and its descendants, or until we decide that there are no more matches
+   * for this batch and root fragment.
+   */
+  while (true)
+  {
+    if (m_iterState == Iter_notStarted)
+    {
+      // Fetch first row for this stream
+      if (isRoot)
+      {
+        m_currentRow = 0;
+        if (getReceiver().m_result_rows == 0)
+        {
+          m_iterState = Iter_finished;
+        }
+        else
+        {
+          m_iterState = Iter_stepSelf;
+        }
+      }
+      else
+      {
+        assert (parentId != tupleNotFound);
+        m_currentParentId = parentId;
+        if (findTupleWithParentId(parentId) == tupleNotFound)
+        {
+          m_iterState = Iter_finished;
+        }
+        else
+        {
+          m_iterState = Iter_stepSelf;
+        }
+      }
+    }
+    else if (m_iterState == Iter_stepSelf)
+    {
+      // Fetch next row for this stream
+      if (isRoot)
+      {
+        m_currentRow++;
+        if (m_currentRow >= getReceiver().m_result_rows)
+        {
+          m_iterState = Iter_finished;
+        }
+      }
+      else
+      {
+        if (findNextTuple() == tupleNotFound)
+        {
+          m_iterState = Iter_finished;
+        }
+      } 
+    }
+
+    if (m_iterState == Iter_finished)
+    {
+      if (isRoot)
+      {
+        return ScanRowResult_endOfScan;
+      }
+      else
+      {
+#if 0
+        return ScanRowResult_endOfBatch;
+#else
+        // FIXME!!! (Handle left outer join properly.)
+        m_operation.nullifyResult();
+        return ScanRowResult_endOfScan;
+#endif
+      }
+    }
+
+    bool childRowsOk = true;
+    Uint32 childNo = 0;
+    Uint32 childrenWithRows = 0;
+    /* Call recursively for the children of this operation.*/
+    while (childRowsOk && childNo < m_operation.getNoOfChildOperations())
+    {
+      NdbQueryOperationImpl& child = m_operation.getChildOperation(childNo);
+      
+      /* If we fetched a new row for this operation, then we should get a
+       * new row for each child also.
+       * If we did not fetch a new row for this operation, then we should only
+       * get new rows for the child which has a scan desecendant (if there
+       * is such a child.)*/
+      if (m_iterState == Iter_stepSelf 
+          || child.getQueryOperationDef().hasScanDescendant())
+      {
+        switch(child.getResultStream(m_rootFragNo)
+               .getNextScanRow(getTupleId(m_currentRow)))
+        {
+        case ScanRowResult_gotRow:
+          childrenWithRows++;
+          break;
+        case ScanRowResult_endOfScan:
+          if (child.getQueryOperationDef().getMatchType() 
+              != NdbQueryOptions::MatchAll)
+          {
+            /* This must be an inner join.*/
+            childRowsOk = false;
+          }
+          break;
+        case ScanRowResult_endOfBatch:
+          childRowsOk = false;
+          break;
+        default:
+          assert(false);
+        }
+      }
+      childNo++;
+    }
+    if (m_iterState != Iter_stepSelf && childrenWithRows == 0)
+    {
+      /* A row with "NULL" children should have been issued on the last call.
+       * We should fetch the next row for this operation.*/
+      childRowsOk = false;
+    }
+
+    if (!childRowsOk || childrenWithRows == 0)
+    {
+      // Fetch a new row for this operation next time.
+      m_iterState = Iter_stepSelf;
+    }
+    else
+    {
+      // Keep iterating over child rows.
+      m_iterState = Iter_stepChild;
+    }
+
+    if (childRowsOk)
+    {
+      getReceiver().setCurrentRow(m_currentRow);
+      m_operation.fetchRow(*this);
+      return ScanRowResult_gotRow;
+    }
+  } // while(true)
+} //NdbResultStream::getNextScanRow()
+
 
 ///////////////////////////////////////////
 /////////  NdbRootFragment methods ///////////
@@ -561,20 +744,16 @@ NdbRootFragment::NdbRootFragment():
   m_query(NULL),
   m_fragNo(voidFragNo),
   m_outstandingResults(0),
-  m_confReceived(false),
-  m_currentTuple(0),
-  m_tupleIdx(NULL)
+  m_confReceived(false)
 {
 }
 
 
-Uint32 NdbRootFragment::init(NdbQueryImpl& query, Uint32 fragNo)
+void NdbRootFragment::init(NdbQueryImpl& query, Uint32 fragNo)
 {
   assert(m_fragNo==voidFragNo);
   m_query = &query;
   m_fragNo = fragNo;
-  m_tupleIdx = new Uint16[query.getScan(0).getMaxBatchRows()*(query.getScanCount()+1)];
-  return m_tupleIdx == NULL ? Err_MemoryAlloc : 0; 
 }
 
 void NdbRootFragment::reset()
@@ -582,7 +761,6 @@ void NdbRootFragment::reset()
   assert(m_fragNo!=voidFragNo);
   assert(m_outstandingResults == 0);
   assert(m_confReceived);
-  m_currentTuple = 0;
   m_confReceived = false;
 }
 
@@ -601,150 +779,20 @@ bool NdbRootFragment::finalBatchReceived
   return getResultStream(0).getReceiver().m_tcPtrI==RNIL;
 }
 
-bool NdbRootFragment::isEmpty() const
+
+bool  NdbRootFragment::isEmpty() const
 { 
   if (m_query->getQueryDef().isScanQuery())
   {
-    /* We iterate over the tuples of the bottom scan operation.
-     * When we have consumed all of these (for this batch and root fragment),
-     * this NdbRootFragment is empty.
-     */
-    return m_currentTuple == 
-      m_query->getScan(m_query->getScanCount()-1)
-      .getResultStream(m_fragNo).getReceiver().m_result_rows;
+    return m_query->getQueryOperation(0U).getResultStream(m_fragNo)
+      .m_iterState == NdbResultStream::Iter_finished;
   }
   else
   {
-    return !m_query->getQueryOperation(0U).getReceiver(m_fragNo).nextResult(); 
-  }
-}
-
-int compareTupleNoArrays(const void* bufferA, const void* bufferB)
-{
-  const Uint16* const arrayA = reinterpret_cast<const Uint16*>(bufferA);
-  const Uint16* const arrayB = reinterpret_cast<const Uint16*>(bufferB);
-  const Uint32 length = arrayA[0];
-  assert(length == arrayB[0]);
-  for (Uint32 i = 1; i<length; i++)
-  {
-    if (arrayA[i] < arrayB[i])
-    {
-      return -1;
-    } 
-    else if (arrayA[i] > arrayB[i])
-    {
-      return 1;
-    }
-  }
-  return 0;
-}
-
-void NdbRootFragment::buildResultIndex()
-{
-  const Uint32 scanCount = m_query->getScanCount();
-  assert(scanCount > 0);
-  /* The 'bottomScan' is the only scan operation that has no scan descdendants.
-   * Whever we get a new batch, there will be a new set of tuples for the 
-   * bottom scan. We should therefor make sure to consume these before asking
-   * for a new batch. (For inner joins, this is all we need to do.)
-   */
-  const NdbQueryOperationImpl& bottomScan = m_query->getScan(scanCount-1);
-  const NdbReceiver& bottomReceiver = 
-    bottomScan.getResultStream(getFragNo()).getReceiver();
-
-  /* Find operation number of the bottom scan. (Operations within a query
-   * are numbered from 0 and onwards.)
-   */
-  Uint32 bottomOpNo = 0xffffffff;
-  for (Uint32 i = 0; i<m_query->getNoOfOperations(); i++)
-  {
-    if (&bottomScan == &m_query->getQueryOperation(i))
-    {
-      bottomOpNo = i;
-    }
-  }
-
-  /* Iterate over the rows from the bottom scan and find matching rows from
-   * the other scan operations.
-   */
-  for (Uint32 bottomTupNo = 0;
-       bottomTupNo < bottomReceiver.m_result_rows;
-       bottomTupNo ++)
-  {
-    /* Add a length field, soo that the qsort compare function can know the 
-     * number of scans to consider (see compareTupleNoArrays()).
-     */
-    m_tupleIdx[bottomTupNo*(scanCount+1)] = scanCount;
-    /* Enter the rows of the bottom scan in the order in which they arrived.
-     */
-    m_tupleIdx[bottomTupNo*(scanCount+1) + scanCount] = bottomTupNo;
-    Uint32 childTupNo = bottomTupNo;
-    Uint32 scanNo = scanCount-1;
-    
-    /* For all other scans, enter the number of the row that corresponds to the
-     * current row of the bottom scan.
-     */
-    for (int opNo = bottomOpNo-1; opNo>=0; opNo--)
-    {
-      const NdbResultStream& childStream = m_query->getQueryOperation(opNo+1)
-        .getResultStream(getFragNo());
-      const NdbResultStream& stream = m_query->getQueryOperation(opNo)
-        .getResultStream(getFragNo());
-
-      const Uint16 tupleId = childStream.getParentId(childTupNo);
-      assert(tupleId != tupleNotFound);
-      const Uint16 tupleNo = stream.findTupleWithId(tupleId);
-      assert(tupleNo != tupleNotFound);
-      if (m_query->getQueryOperation(opNo).getQueryOperationDef()
-          .isScanOperation())
-      {
-        scanNo--;
-        m_tupleIdx[bottomTupNo*(scanCount+1)+scanNo+1] = tupleNo;
-      }
-      childTupNo = tupleNo;
-    }
-    assert(scanNo == 0);
+    return !m_query->getQueryOperation(0U).getReceiver(m_fragNo).nextResult();
   }
-  qsort(m_tupleIdx, bottomReceiver.m_result_rows, (scanCount+1)*sizeof(Uint16),
-        compareTupleNoArrays);
 }
 
-bool 
-NdbRootFragment::fetchScanResults()
-{
-  const Uint32 scanCount = m_query->getScanCount();
-  /* Get a new row for each scan operation.*/
-  for (Uint32 scanNo = 0; scanNo < scanCount; scanNo++)
-  {
-    // m_tupleIdx tells us which row to use for each operation and iteation.
-    const Uint16 rowNo = m_tupleIdx[(scanCount+1)*m_currentTuple + scanNo + 1];
-    NdbQueryOperationImpl& scan = m_query->getScan(scanNo);
-    NdbResultStream& resultStream = scan.getResultStream(getFragNo());
-    resultStream.getReceiver().setCurrentRow(rowNo);
-    /* Call recursively for the lookup descendants of this operation.*/
-    for (Uint32 i = 0; i<scan.getNoOfChildOperations(); i++)
-    {
-      NdbQueryOperationImpl& child = scan.getChildOperation(i);
-      if (!child.getQueryOperationDef().isScanOperation())
-      {
-        const bool nullRow = 
-          !child.fetchSubLookupResults(getFragNo(), 
-                                       resultStream.getTupleId(rowNo));
-        if (nullRow &&
-            child.getQueryOperationDef().getMatchType() != NdbQueryOptions::MatchAll)
-        {
-          // If a NULL row is returned from a child which is not outer joined, 
-          // parent row may be eliminate also.
-          scan.nullifyResult();
-          return false;
-        }
-      }
-    }
-    m_query->getScan(scanNo).fetchRow(resultStream);
-  }
-  m_currentTuple++;
-  return true;
-} //NdbRootFragment::fetchScanResults
 
 ///////////////////////////////////////////
 /////////  NdbQuery API methods ///////////
@@ -1163,10 +1211,6 @@ NdbQueryImpl::NdbQueryImpl(NdbTransactio
   {
     const NdbQueryOperationDefImpl& def = queryDef.getQueryOperation(i);
     new(&m_operations[i]) NdbQueryOperationImpl(*this, def);
-    if (def.isScanOperation())
-    {
-      m_scans[m_scanCount++] = &m_operations[i];
-    }
   }
 
   // Serialized QueryTree definition is first part of ATTRINFO.
@@ -1547,11 +1591,13 @@ NdbQueryImpl::nextResult(bool fetchAllow
     }
 
     NdbQueryOperationImpl& root = getRoot();
+    NdbResultStream& rootStream = m_applFrags.getCurrent()->getResultStream(0);
     bool gotRow = false;
 
     /* Make results from root operation available to the user.*/
     if (m_queryDef.isScanQuery()) {
-      gotRow = m_applFrags.getCurrent()->fetchScanResults();
+      gotRow = (rootStream.getNextScanRow(tupleNotFound) 
+                == NdbResultStream::ScanRowResult_gotRow);
 
       /* In case we are doing an ordered index scan, reorder the root fragments
        * such that we get the next record from the right fragment.
@@ -1621,7 +1667,6 @@ NdbQueryImpl::fetchMoreResults(bool forc
 
       NdbRootFragment* frag;
       while ((frag=m_fullFrags.pop()) != NULL) {
-        frag->buildResultIndex();
         m_applFrags.add(*frag);
       }
 
@@ -1944,13 +1989,7 @@ NdbQueryImpl::prepareSend()
   {
     for(Uint32 i = 0; i<m_rootFragCount; i++)
     {
-      // Set fragment number.
-      const Uint32 error = m_rootFrags[i].init(*this, i); 
-      if (error != 0) 
-      {
-        setErrorCodeAbort(error);
-        return -1;
-      }
+      m_rootFrags[i].init(*this, i); // Set fragment number.
     }
   }
 
@@ -3231,47 +3270,6 @@ NdbQueryOperationImpl::fetchRow(NdbResul
   }
 } // NdbQueryOperationImpl::fetchRow
 
-bool 
-NdbQueryOperationImpl::fetchSubLookupResults(Uint32 fragNo, 
-                                             Uint16 parentId)
-{
-  assert(!getQueryOperationDef().isScanOperation());
-  assert(parentId != tupleNotFound);
-  /* Use random rather than sequential access on receiver, since we
-   * iterate over results being indexed by 'parentId'
-   */
-  NdbResultStream& resultStream = getResultStream(fragNo);
-  const Uint32 rowNo = resultStream.findTupleWithParentId(parentId);
-  if (rowNo == tupleNotFound)
-  {
-    /* This operation retrieved no result for the current parent tuple.*/
-    nullifyResult();
-    return false;
-  }
-  resultStream.getReceiver().setCurrentRow(rowNo);
-
-  /* Call recursively for the children of this operation.*/
-  for (Uint32 i = 0; i<getNoOfChildOperations(); i++)
-  {
-    NdbQueryOperationImpl& child = getChildOperation(i);
-    if (!child.getQueryOperationDef().isScanOperation())
-    {
-      const bool nullRow = 
-        !child.fetchSubLookupResults(fragNo, resultStream.getTupleId(rowNo));
-        if (nullRow &&
-            child.m_operationDef.getMatchType() != NdbQueryOptions::MatchAll)
-        {
-          // If a NULL row is returned from a child which is not outer joined, 
-          // parent row may be eliminate also.
-          (void)resultStream.getReceiver().get_row();  // Get and throw 
-          nullifyResult();
-          return false;
-        }
-      }
-  }
-  fetchRow(resultStream);
-  return true;
-}
 
 bool 
 NdbQueryOperationImpl::fetchLookupResults()

=== modified file 'storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp	2010-07-14 22:09:14 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp	2010-07-15 14:14:24 +0000
@@ -197,15 +197,6 @@ public:
   Uint32 getRootFragCount() const
   { return m_rootFragCount; }
 
-  Uint32 getScanCount() const
-  { return m_scanCount; }
-
-  NdbQueryOperationImpl& getScan(Uint32 scanNo) const
-  {
-    assert(scanNo < m_scanCount);
-    return *m_scans[scanNo];
-  }
-
 private:
   /** Possible return values from NdbQuery::fetchMoreResults. Integer values
    * matches those returned from PoolGuard::waitScan().
@@ -573,8 +564,6 @@ public:
   bool checkMagicNumber() const
   { return m_magic == MAGIC; }
 
-  bool fetchSubLookupResults(Uint32 rootFragNo, Uint16 parentId);
-
   /** Copy NdbRecAttr and/or NdbRecord results into appl. buffers */
   void fetchRow(NdbResultStream& src);
 
@@ -658,7 +647,7 @@ private:
   /** Release resources after scan has returned last available result */
   void postFetchRelease();
 
-  /** Fetch results for scan or lookup operation.
+  /** Fetch results for lookup operation.
    *  Recursively fetchRow() for 'this' operation and all its
    *  descendant child operations.
    *  Return true if a row was fetched, or false if a NULL row was


Attachment: [text/bzr-bundle] bzr/jan.wedvik@sun.com-20100715175157-960fqmjy0a9y4rvh.bundle
Thread
bzr push into mysql-5.1-telco-7.0-spj-scan-vs-scan branch (jan.wedvik:3206to 3211) Jan Wedvik15 Jul