List:Commits« Previous MessageNext Message »
From:Jonas Oreland Date:April 30 2010 11:03am
Subject:bzr commit into mysql-5.1-telco-7.0-spj branch (jonas:3145)
View as plain text  
#At file:///home/jonas/src/70-spj/ based on revid:jonas@stripped

 3145 Jonas Oreland	2010-04-30 [merge]
      ndb spj - merge DbspjMain extension to interpreted programs

    modified:
      storage/ndb/include/kernel/signaldata/DbspjErr.hpp
      storage/ndb/include/kernel/signaldata/QueryTree.hpp
      storage/ndb/include/kernel/signaldata/ScanTab.hpp
      storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp
      storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp
      storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp
      storage/ndb/test/tools/Makefile.am
      storage/ndb/test/tools/test_spj.cpp
=== modified file 'storage/ndb/include/kernel/signaldata/DbspjErr.hpp'
--- a/storage/ndb/include/kernel/signaldata/DbspjErr.hpp	2009-05-04 07:12:52 +0000
+++ b/storage/ndb/include/kernel/signaldata/DbspjErr.hpp	2010-04-29 14:56:00 +0000
@@ -30,6 +30,9 @@ struct DbspjErr
     ,OutOfQueryMemory = 20008
     ,QueryNodeTooBig = 20009
     ,QueryNodeParametersTooBig = 20010
+    ,BothTreeAndParametersContainInterpretedProgram = 20011
+    ,InvalidTreeParametersSpecificationKeyParamBitsMissmatch = 20012
+    ,InvalidTreeParametersSpecificationIncorrectKeyParamCount = 20013
   };
 };
 

=== modified file 'storage/ndb/include/kernel/signaldata/QueryTree.hpp'
--- a/storage/ndb/include/kernel/signaldata/QueryTree.hpp	2010-02-24 14:09:54 +0000
+++ b/storage/ndb/include/kernel/signaldata/QueryTree.hpp	2010-04-29 14:56:00 +0000
@@ -79,31 +79,41 @@ struct DABits
 
     NI_KEY_LINKED     = 0x02,  // Does keyinfo contain linked values
     NI_KEY_PARAMS     = 0x04,  // Does keyinfo contain parameters
-    NI_KEY_CONSTS     = 0x08,  // Does keyinfo contain const operands.
+    NI_KEY_CONSTS     = 0x08,  // Does keyinfo contain const values
 
     NI_LINKED_ATTR    = 0x10,  // List of attributes to be used by children
+
     NI_ATTR_INTERPRET = 0x20,  // Is attr-info a interpreted program
     NI_ATTR_PARAMS    = 0x40,  // Does attrinfo contain parameters
     NI_ATTR_LINKED    = 0x80,  // Does attrinfo contain linked values
+
     /**
      * Iff this flag is set, then this operation has a child operation with a 
      * linked value that refes to a disk column of this operation. For example
      * SELECT * FROM t1, t2 WHERE t1.disk_att = t2.primary_key;  
      */
     NI_LINKED_DISK    = 0x100, 
+
     NI_END = 0
   };
 
   enum ParamInfoBits
   {
     PI_ATTR_LIST   = 0x1, // "user" projection list
+
+    /**
+     * These 2 must match their resp. QueryNode-definitions
+     */
     PI_ATTR_PARAMS = 0x2, // attr-info parameters (NI_ATTR_PARAMS)
     PI_KEY_PARAMS  = 0x4, // key-info parameters  (NI_KEY_PARAMS)
+
     /** 
      * The parameter object contains a program that will be interpreted 
      * before reading the attributes (i.e. a scan filter).
+     * NOTE: Can/should not be used if QueryNode contains interpreted program
      */
     PI_ATTR_INTERPRET = 0x8,
+
     /**
      * Iff this flag is set, then the user projection for this operation 
      * contains at least one disk column.   
@@ -207,10 +217,12 @@ struct QueryPattern
   Uint32 m_info;
   enum
   {
-    P_DATA   = 0x1, // Raw data of len-words (constants)
-    P_COL    = 0x2, // Get column value from RowRef
-    P_UNQ_PK = 0x3, // NDB$PK column from a unique index
-    P_PARAM  = 0x4, // User specified parameter value
+    P_DATA   = 0x1,  // Raw data of len-words (constants)
+    P_COL    = 0x2,  // Get column value from RowRef
+    P_UNQ_PK = 0x3,  // NDB$PK column from a unique index
+    P_PARAM  = 0x4,  // User specified parameter value
+    P_PARAM_HEADER = 0x6, // User specified param val including AttributeHeader
+    P_ATTRINFO = 0x7,// Get column including header from RowRef
     P_END    = 0
   };
 

=== modified file 'storage/ndb/include/kernel/signaldata/ScanTab.hpp'
--- a/storage/ndb/include/kernel/signaldata/ScanTab.hpp	2009-10-02 13:26:22 +0000
+++ b/storage/ndb/include/kernel/signaldata/ScanTab.hpp	2010-04-29 14:56:00 +0000
@@ -39,6 +39,7 @@ class ScanTabReq {
   friend class NdbScanOperation;
   friend class NdbIndexScanOperation;
   friend class NdbQueryImpl;
+  friend class NdbScanFilterImpl;
 
   /**
    * For printing

=== modified file 'storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp	2010-03-09 20:04:49 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp	2010-04-29 14:56:00 +0000
@@ -307,7 +307,6 @@ public:
       m_send.m_correlation = 0;
       m_send.m_keyInfoPtrI = RNIL;
       m_send.m_attrInfoPtrI = RNIL;
-      m_send.m_attrInfoParamPtrI = RNIL;
     };
 
     const Uint32 m_magic;
@@ -409,7 +408,6 @@ public:
       Uint32 m_correlation;
       Uint32 m_keyInfoPtrI;      // keyInfoSection
       Uint32 m_attrInfoPtrI;     // attrInfoSection
-      Uint32 m_attrInfoParamPtrI;// attrInfoParamSection
     } m_send;
 
     union {
@@ -599,7 +597,8 @@ private:
   void getCorrelationData(const RowRef::Section & row, Uint32 col,
                           Uint32& rootStreamId, Uint32& correlationNumber);
   Uint32 appendToPattern(Local_pattern_store &, DABuffer & tree, Uint32);
-  Uint32 appendColToPattern(Local_pattern_store&,const RowRef::Linear&, Uint32);
+  Uint32 appendParamToPattern(Local_pattern_store&,const RowRef::Linear&,
+                              Uint32);
 
   Uint32 appendTreeToSection(Uint32 & ptrI, SectionReader &, Uint32);
   Uint32 appendColToSection(Uint32 & ptrI, const RowRef::Linear&, Uint32 col);
@@ -608,6 +607,8 @@ private:
   Uint32 appendDataToSection(Uint32 & ptrI, Local_pattern_store&,
 			     Local_pattern_store::ConstDataBufferIterator&,
 			     Uint32 len);
+  Uint32 appendAttrinfoToSection(Uint32&, const RowRef::Linear&, Uint32 col);
+  Uint32 appendAttrinfoToSection(Uint32&, const RowRef::Section&, Uint32 col);
   Uint32 expand(Uint32 & ptrI, Local_pattern_store&, const RowRef::Section&);
   Uint32 expand(Uint32 & ptrI, DABuffer& pattern, Uint32 len,
                 DABuffer & param, Uint32 cnt);

=== modified file 'storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp	2010-04-08 13:32:24 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp	2010-04-29 14:56:00 +0000
@@ -828,12 +828,6 @@ Dbspj::cleanup_common(Ptr<Request> reque
     jam();
     releaseSection(treeNodePtr.p->m_send.m_attrInfoPtrI);
   }
-
-  if (treeNodePtr.p->m_send.m_attrInfoParamPtrI != RNIL)
-  {
-    jam();
-    releaseSection(treeNodePtr.p->m_send.m_attrInfoParamPtrI);
-  }
 }
 
 /**
@@ -1200,6 +1194,12 @@ Dbspj::lookup_build(Build_context& ctx,
       break;
     }
 
+    if (treeNodePtr.p->m_bits & TreeNode::T_ATTR_INTERPRETED)
+    {
+      jam();
+      LqhKeyReq::setInterpretedFlag(dst->requestInfo, 1);
+    }
+
     treeNodePtr.p->m_state = TreeNode::TN_INACTIVE;
 
     return 0;
@@ -1354,7 +1354,7 @@ Dbspj::lookup_send(Signal* signal,
   getSection(handle.m_ptr[1], attrInfoPtrI);
   handle.m_cnt = 2;
 
-#ifdef DEBUG_LQHKEYREQ
+#if defined DEBUG_LQHKEYREQ
   ndbout_c("LQHKEYREQ to %x", ref);
   printLQHKEYREQ(stdout, signal->getDataPtrSend(),
 		 NDB_ARRAY_SIZE(treeNodePtr.p->m_lookup_data.m_lqhKeyReq),
@@ -1589,6 +1589,38 @@ Dbspj::lookup_start_child(Signal* signal
     if (unlikely(err != 0))
       break;
 
+    Uint32 attrInfoPtrI = treeNodePtr.p->m_send.m_attrInfoPtrI;
+    if (treeNodePtr.p->m_bits & TreeNode::T_ATTRINFO_CONSTRUCTED)
+    {
+      jam();
+      Uint32 tmp = RNIL;
+      ndbrequire(dupSection(tmp, attrInfoPtrI)); // TODO handle error
+
+      Uint32 org_size;
+      {
+        SegmentedSectionPtr ptr;
+        getSection(ptr, tmp);
+        org_size = ptr.sz;
+      }
+
+      LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
+      Local_pattern_store pattern(pool, treeNodePtr.p->m_attrParamPattern);
+      err = expand(tmp, pattern, rowRef.m_row_data.m_section);
+      if (unlikely(err != 0))
+        break;
+
+      /**
+       * Update size of subsrouting section, which contains arguments
+       */
+      SegmentedSectionPtr ptr;
+      getSection(ptr, tmp);
+      Uint32 new_size = ptr.sz;
+      Uint32 * sectionptrs = ptr.p->theData;
+      sectionptrs[4] = new_size - org_size;
+
+      treeNodePtr.p->m_send.m_attrInfoPtrI = tmp;
+    }
+
     /**
      * Now send...
      */
@@ -1619,6 +1651,13 @@ Dbspj::lookup_start_child(Signal* signal
       LqhKeyReq::setDistributionKey(attrLen, tmp.fragDistKey);
       dst->attrLen = attrLen;
       lookup_send(signal, requestPtr, treeNodePtr);
+
+      if (treeNodePtr.p->m_bits & TreeNode::T_ATTRINFO_CONSTRUCTED)
+      {
+        jam();
+        // restore
+        treeNodePtr.p->m_send.m_attrInfoPtrI = attrInfoPtrI;
+      }
     }
     return;
   } while (0);
@@ -2582,7 +2621,7 @@ Dbspj::appendToPattern(Local_pattern_sto
 }
 
 Uint32
-Dbspj::appendColToPattern(Local_pattern_store& dst,
+Dbspj::appendParamToPattern(Local_pattern_store& dst,
                           const RowRef::Linear & row, Uint32 col)
 {
   /**
@@ -2689,6 +2728,46 @@ Dbspj::appendColToSection(Uint32 & dst, 
   return appendToSection(dst, ptr, len) ? 0 : DbspjErr::InvalidPattern;
 }
 
+Uint32
+Dbspj::appendAttrinfoToSection(Uint32 & dst, const RowRef::Linear & row, 
+                               Uint32 col)
+{
+  /**
+   * TODO handle errors
+   */
+  const Uint32 * header = (const Uint32*)row.m_header->m_headers;
+  Uint32 offset = 0;
+  for (Uint32 i = 0; i<col; i++)
+  {
+    offset += 1 + AttributeHeader::getDataSize(* header++);
+  }
+  const Uint32 * ptr = row.m_data + offset;
+  Uint32 len = AttributeHeader::getDataSize(* ptr);
+  return appendToSection(dst, ptr, 1 + len) ? 0 : DbspjErr::InvalidPattern;
+}
+
+Uint32
+Dbspj::appendAttrinfoToSection(Uint32 & dst, const RowRef::Section & row, 
+                               Uint32 col)
+{
+  /**
+   * TODO handle errors
+   */
+  const Uint32 * header = (const Uint32*)row.m_header->m_headers;
+  SegmentedSectionPtr ptr(row.m_dataPtr);
+  SectionReader reader(ptr, getSectionSegmentPool());
+  Uint32 offset = 0;
+  for (Uint32 i = 0; i<col; i++)
+  {
+    offset += 1 + AttributeHeader::getDataSize(* header++);
+  }
+  ndbrequire(reader.step(offset));
+  Uint32 tmp;
+  ndbrequire(reader.peekWord(&tmp));
+  Uint32 len = AttributeHeader::getDataSize(tmp);
+  return appendTreeToSection(dst, reader, 1 + len);
+}
+
 /**
  * 'PkCol' is the composite NDB$PK column in an unique index consisting of
  * a fragment id and the composite PK value (all PK columns concatenated)
@@ -2847,12 +2926,17 @@ Dbspj::expand(Uint32 & _dst, Local_patte
       jam();
       err = appendPkColToSection(dst, row, val);
       break;
+    case QueryPattern::P_ATTRINFO:
+      jam();
+      err = appendAttrinfoToSection(dst, row, val);
+      break;
     case QueryPattern::P_DATA:
       jam();
       err = appendDataToSection(dst, pattern, it, val);
       break;
     // PARAM's converted to DATA by ::expand(pattern...)
     case QueryPattern::P_PARAM:
+    case QueryPattern::P_PARAM_HEADER:
     default:
       jam();
       err = DbspjErr::InvalidPattern;
@@ -2902,6 +2986,11 @@ Dbspj::expand(Uint32 & ptrI, DABuffer& p
       ndbassert(val < paramCnt);
       err = appendColToSection(dst, row, val);
       break;
+    case QueryPattern::P_PARAM_HEADER:
+      jam();
+      ndbassert(val < paramCnt);
+      err = appendAttrinfoToSection(dst, row, val);
+      break;
     case QueryPattern::P_DATA:
       if (likely(appendToSection(dst, ptr, val)))
       {
@@ -2916,9 +3005,11 @@ Dbspj::expand(Uint32 & ptrI, DABuffer& p
       ptr += val;
       break;
     case QueryPattern::P_COL: // (linked) COL's not expected here
+    case QueryPattern::P_ATTRINFO:
     case QueryPattern::P_UNQ_PK:
     default:
       jam();
+      jamLine(type);
       err = DbspjErr::InvalidPattern;
       DEBUG_CRASH();
     }
@@ -2975,6 +3066,7 @@ Dbspj::expand(Local_pattern_store& dst, 
     switch(type){
     case QueryPattern::P_COL:
     case QueryPattern::P_UNQ_PK:
+    case QueryPattern::P_ATTRINFO:
       jam();
       err = appendToPattern(dst, pattern, 1);
       break;
@@ -2986,8 +3078,19 @@ Dbspj::expand(Local_pattern_store& dst, 
       jam();
       // NOTE: Converted to P_DATA by appendColToPattern
       ndbassert(val < paramCnt);
-      err = appendColToPattern(dst, row, val);
+      err = appendParamToPattern(dst, row, val);
+      pattern.ptr++;
+      break;
+    case QueryPattern::P_PARAM_HEADER:
+      jam();
+#if 0
+      // NOTE: Converted to P_DATA by appendParamToPattern
+      ndbassert(val < paramCnt);
+      err = appendParamHeadToPattern(dst, row, val);
       pattern.ptr++;
+#else
+      ndbrequire(false);
+#endif
       break;
    default:
       jam();
@@ -3062,8 +3165,13 @@ Dbspj::parseDA(Build_context& ctx,
         break;
     }
 
-    ndbrequire(((treeBits  & DABits::NI_KEY_PARAMS)==0)
-            == ((paramBits & DABits::PI_KEY_PARAMS)==0));
+    err = DbspjErr::InvalidTreeParametersSpecificationKeyParamBitsMissmatch;
+    if (unlikely(! (((treeBits  & DABits::NI_KEY_PARAMS)==0) ==
+                    ((paramBits & DABits::PI_KEY_PARAMS)==0))))
+    {
+      DEBUG_CRASH();
+      break;
+    }
 
     if (treeBits & (DABits::NI_KEY_PARAMS 
 		    | DABits::NI_KEY_LINKED 
@@ -3085,8 +3193,13 @@ Dbspj::parseDA(Build_context& ctx,
       LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
       Local_pattern_store pattern(pool, treeNodePtr.p->m_keyPattern);
 
-      ndbrequire((cnt==0) == ((treeBits & DABits::NI_KEY_PARAMS) ==0));
-      ndbrequire((cnt==0) == ((paramBits & DABits::PI_KEY_PARAMS)==0));
+      err = DbspjErr::InvalidTreeParametersSpecificationIncorrectKeyParamCount;
+      if (unlikely(!(((cnt==0) == ((treeBits & DABits::NI_KEY_PARAMS) == 0)) &&
+                     ((cnt==0) == ((paramBits & DABits::PI_KEY_PARAMS) == 0)))))
+      {
+        DEBUG_CRASH();
+        break;
+      }
 
       if (treeBits & DABits::NI_KEY_LINKED)
       {
@@ -3148,7 +3261,7 @@ Dbspj::parseDA(Build_context& ctx,
        *   DATA1..N     = PARAM-0...PARAM-M
        *
        * IF PI_ATTR_INTERPRET
-       *   DATA0[LO] = Length of program
+       *   DATA0[LO/HI] = Length of program / Length of subroutine-part
        *   DATA1..N     = Program (scan filter)
        *
        * IF NI_ATTR_LINKED
@@ -3161,8 +3274,9 @@ Dbspj::parseDA(Build_context& ctx,
 
       bool interpreted =
         (treeBits & DABits::NI_ATTR_INTERPRET) ||
+        (paramBits & DABits::PI_ATTR_INTERPRET) ||
         (treeNodePtr.p->m_bits & TreeNode::T_ATTR_INTERPRETED);
-
+      
       if (interpreted)
       {
         /**
@@ -3184,62 +3298,58 @@ Dbspj::parseDA(Build_context& ctx,
         if (treeBits & DABits::NI_ATTR_INTERPRET)
         {
           jam();
+
           /** 
            * Having two interpreter programs is an error.
            */
-          ndbrequire(!(paramBits & DABits::PI_ATTR_INTERPRET));
-          Uint32 cnt_len = * tree.ptr++;
-          Uint32 len = cnt_len & 0xFFFF; // Length of interpret program
-          Uint32 cnt = cnt_len >> 16;    // #Arguments to program
+          err = DbspjErr::BothTreeAndParametersContainInterpretedProgram;
+          if (unlikely(paramBits & DABits::PI_ATTR_INTERPRET))
+          {
+            DEBUG_CRASH();
+            break;
+          }
+
+          treeNodePtr.p->m_bits |= TreeNode::T_ATTR_INTERPRETED;
+          Uint32 len2 = * tree.ptr++;
+          Uint32 len_prg = len2 & 0xFFFF; // Length of interpret program
+          Uint32 len_pattern = len2 >> 16;// Length of attr param pattern
           err = DbspjErr::OutOfSectionMemory;
-          if (unlikely(!appendToSection(attrInfoPtrI, tree.ptr, len)))
+          if (unlikely(!appendToSection(attrInfoPtrI, tree.ptr, len_prg)))
           {
             DEBUG_CRASH();
             break;
           }
 
-          tree.ptr += len;
-          sectionptrs[1] = len; // size of interpret program
+          tree.ptr += len_prg;
+          sectionptrs[1] = len_prg; // size of interpret program
+
+          Uint32 tmp = * tree.ptr ++; // attr-pattern header
+          Uint32 cnt = tmp & 0xFFFF;
 
-          if (cnt)
+          if (treeBits & DABits::NI_ATTR_LINKED)
           {
             jam();
-            err = DbspjErr::InvalidTreeNodeSpecification;
-            const Uint32 check = DABits::NI_ATTR_PARAMS|DABits::NI_ATTR_LINKED;
-            if (unlikely((treeBits & check) == 0))
-            {
-              /**
-               * If program has arguments, it must either has
-               *   DABits::NI_ATTR_PARAMS - i.e parameters
-               *   DABits::NI_ATTR_LINKED - i.e linked
-               */
-              DEBUG_CRASH();
-              break;
-            }
-
             /**
-             * Prepare directory for parameters
+             * Expand pattern into a new pattern (with linked values)
              */
-            err = zeroFill(attrParamPtrI, cnt);
-            if (unlikely(err != 0))
-            {
-              DEBUG_CRASH();
-              break;
-            }
-
+            LocalArenaPoolImpl pool(requestPtr.p->m_arena, 
+                                    m_dependency_map_pool);
+            Local_pattern_store pattern(pool,treeNodePtr.p->m_attrParamPattern);
+            err = expand(pattern, tree, len_pattern, param, cnt);
+            
             /**
-             * TODO...continue here :-(
+             * This node constructs a new attr-info for each send
              */
-            ndbrequire(false);
+            treeNodePtr.p->m_bits |= TreeNode::T_ATTRINFO_CONSTRUCTED;
           }
-
-          if (treeBits & DABits::NI_ATTR_LINKED)
+          else
           {
             jam();
             /**
-             * The parameter section is recreated prior to each send...
+             * Expand pattern directly into attr-info param
+             *   This means a "fixed" attr-info param from here on
              */
-            treeNodePtr.p->m_bits |= TreeNode::T_ATTRINFO_CONSTRUCTED;
+            err = expand(attrParamPtrI, tree, len_pattern, param, cnt);
           }
         }
         else // if (treeBits & DABits::NI_ATTR_INTERPRET)
@@ -3252,9 +3362,10 @@ Dbspj::parseDA(Build_context& ctx,
           ndbrequire((paramBits & DABits::PI_ATTR_PARAMS) == 0);
           ndbrequire((treeBits & DABits::NI_ATTR_LINKED) == 0);
 
-          ndbassert((treeNodePtr.p->m_bits & TreeNode::T_ATTR_INTERPRETED)!= 0);
+          treeNodePtr.p->m_bits |= TreeNode::T_ATTR_INTERPRETED;
 
-          if (!(paramBits & DABits::PI_ATTR_INTERPRET)){
+          if (! (paramBits & DABits::PI_ATTR_INTERPRET))
+          {
             jam();
 
             /**
@@ -3281,26 +3392,35 @@ Dbspj::parseDA(Build_context& ctx,
         /**
          * Add the interpreted code that represents the scan filter.
          */
-        const Uint32 len = * param.ptr++;
-        ndbassert(len <= 0xFFFF);
-        ndbassert(len > 0);
+        const Uint32 len2 = * param.ptr++;
+        Uint32 program_len = len2 & 0xFFFF;
+        Uint32 subroutine_len = len2 >> 16;
         err = DbspjErr::OutOfSectionMemory;
-        if (unlikely(!appendToSection(attrInfoPtrI, param.ptr, len)))
+        if (unlikely(!appendToSection(attrInfoPtrI, param.ptr, program_len)))
         {
           DEBUG_CRASH();
           break;
         }
-        DEBUG("Dbspj::parseDA() adding interpreter program of " 
-              << len << " words.");
-        
-        param.ptr += len;
         /**
          * The interpreted code is added is in the "Interpreted execute region"
          * of the attrinfo (see Dbtup::interpreterStartLab() for details).
          * It will thus execute before reading the attributes that constitutes
          * the projections.
          */
-        sectionptrs[1] = len; 
+        sectionptrs[1] = program_len;
+        param.ptr += program_len;
+        
+        if (subroutine_len)
+        {
+          if (unlikely(!appendToSection(attrParamPtrI, 
+                                        param.ptr, subroutine_len)))
+          {
+            DEBUG_CRASH();
+            break;
+          }
+          sectionptrs[4] = subroutine_len;
+          param.ptr += subroutine_len;
+        }
       }
 
       Uint32 sum_read = 0;
@@ -3379,9 +3499,28 @@ Dbspj::parseDA(Build_context& ctx,
          *   i.e in "final read"-section
          */
         sectionptrs[3] = sum_read;
+
+        if (attrParamPtrI != RNIL)
+        {
+          jam();
+          ndbrequire(!(treeNodePtr.p->m_bits&TreeNode::T_ATTRINFO_CONSTRUCTED));
+
+          SegmentedSectionPtr ptr;
+          getSection(ptr, attrParamPtrI);
+          {
+            SectionReader r0(ptr, getSectionSegmentPool());
+            err = appendTreeToSection(attrInfoPtrI, r0, ptr.sz);
+            sectionptrs[4] = ptr.sz;
+            if (unlikely(err != 0))
+            {
+              DEBUG_CRASH();
+              break;
+            }
+          }
+          releaseSection(attrParamPtrI);
+        }
       }
 
-      treeNodePtr.p->m_send.m_attrInfoParamPtrI = attrParamPtrI;
       treeNodePtr.p->m_send.m_attrInfoPtrI = attrInfoPtrI;
     } // if (((treeBits & mask) | (paramBits & DABits::PI_ATTR_LIST)) != 0)
 

=== modified file 'storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp	2010-04-30 09:41:04 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp	2010-04-30 11:03:17 +0000
@@ -2147,29 +2147,29 @@ Dbtup::lookupInterpreterParameter(Uint32
   /**
    * The parameters...are stored in the subroutine section
    *
-   * WORD0      WORD1      WORD2         WORD3       WORD4         WORD5
-   * [ P0-pos ] [ P1-pos ] [ P0 HEADER ] [ P0 DATA ] [ P1 HEADER ] [ P1 DATA ]
+   * WORD2         WORD3       WORD4         WORD5
+   * [ P0 HEADER ] [ P0 DATA ] [ P1 HEADER ] [ P1 DATA ]
    *
-   * e.g
-   * pos=2      pos=4      [ no=0 len=4]             [ no=1 len=4]
    *
    * len=4 <=> 1 word
    */
-  if (likely(paramNo < sublen))
+  Uint32 pos = 0;
+  while (paramNo)
   {
-    jam();
-    Uint32 pos = subptr[paramNo];
-    if (likely(pos < sublen))
-    {
-      jam();
-      const Uint32 * ptr = subptr + pos;
-      Uint32 len = AttributeHeader::getDataSize(* ptr);
-      Uint32 no = AttributeHeader::getAttributeId(* ptr);
-      if (likely(no == paramNo && (pos + 1 + len) < sublen))
-        return ptr;
-    }
+    const Uint32 * head = subptr + pos;
+    Uint32 len = AttributeHeader::getDataSize(* head);
+    paramNo --;
+    pos += 1 + len;
+    if (unlikely(pos >= sublen))
+      return 0;
   }
-  return 0;
+
+  const Uint32 * head = subptr + pos;
+  Uint32 len = AttributeHeader::getDataSize(* head);
+  if (unlikely(pos + 1 + len > sublen))
+    return 0;
+
+  return head;
 }
 
 int Dbtup::interpreterNextLab(Signal* signal,

=== modified file 'storage/ndb/test/tools/Makefile.am'
--- a/storage/ndb/test/tools/Makefile.am	2010-03-13 10:21:04 +0000
+++ b/storage/ndb/test/tools/Makefile.am	2010-04-29 14:56:00 +0000
@@ -16,7 +16,7 @@
 
 EXTRA_DIST = CMakeLists.txt
 
-ndbtest_PROGRAMS = hugoLoad hugoFill hugoLockRecords hugoPkDelete hugoPkRead hugoPkReadRecord  hugoPkUpdate hugoScanRead hugoScanUpdate restart verify_index copy_tab create_index  ndb_cpcc listen_event eventlog rep_latency ndb_connect spj_sanity_test spj_performance_test
+ndbtest_PROGRAMS = hugoLoad hugoFill hugoLockRecords hugoPkDelete hugoPkRead hugoPkReadRecord  hugoPkUpdate hugoScanRead hugoScanUpdate restart verify_index copy_tab create_index  ndb_cpcc listen_event eventlog rep_latency ndb_connect spj_sanity_test spj_performance_test test_spj
 
 # transproxy 
 
@@ -39,7 +39,17 @@ listen_event_SOURCES = listen.cpp
 eventlog_SOURCES = log_listner.cpp
 rep_latency_SOURCES = rep_latency.cpp
 ndb_connect_SOURCES = connect.cpp
-# test_spj_SOURCES = test_spj.cpp
+test_spj_SOURCES = test_spj.cpp
+test_spj_CXXFLAGS = -I$(top_srcdir)/storage/ndb/include/kernel \
+	-I$(top_srcdir)/storage/ndb/include/transporter \
+	-I$(top_srcdir)/storage/ndb/include/debugger \
+	-I$(top_srcdir)/storage/ndb/include/mgmapi \
+	-I$(top_srcdir)/storage/ndb/include/mgmcommon \
+        -I$(top_srcdir)/storage/ndb/include/ndbapi \
+        -I$(top_srcdir)/storage/ndb/include/util \
+	-I$(top_srcdir)/storage/ndb/include/portlib \
+	-I$(top_srcdir)/storage/ndb/include/logger
+
 spj_sanity_test_SOURCES = spj_sanity_test.cpp
 spj_performance_test_SOURCES = spj_performance_test.cpp
 

=== modified file 'storage/ndb/test/tools/test_spj.cpp'
--- a/storage/ndb/test/tools/test_spj.cpp	2009-10-01 12:41:49 +0000
+++ b/storage/ndb/test/tools/test_spj.cpp	2010-04-29 14:56:00 +0000
@@ -13,20 +13,7 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
-/*
 
-treeSpec: 005f000a 00060001 00000008 00000007 00000001 00020002 babe0003 000a0001 0000000b 00000007 00000001 00000001 00000002 00020001 00020000 00020002 babe0003 000a0001 0000000b 00000007 00000001 00010001 00000002 00020001 00020000 00020002 babe0003 000a0001 0000000b 00000007 00000001 00020001 00000002 00020001 00020000 00020002 babe0003 000a0001 0000000b 00000007 00000001 00030001 00000002 00020001 00020000 00020002 babe0003 000a0001 0000000b 00000007 00000001 00040001 00000002 00020001 00020000 00020002 babe0003 000a0001 0000000b 00000007 00000001 00050001 00000002 00020001 00020000 00020002 babe0003 000a0001 0000000b 00000007 00000001 00060001 00000002 00020001 00020000 00020002 babe0003 000a0001 0000000b 00000007 00000001 00070001 00000002 00020001 00020000 00020002 babe0003 00080001 00000003 00000007 00000001 00080001 00000002 00020001 00020000 
-paramSpec: 00050001 00000001 00000080 00000001 fff00006 00050001 00000001 00000084 00000001 fff00006 00050001 00000001 00000088 00000001 fff00006 00050001 00000001 0000008c 00000001 fff00006 00050001 00000001 00000090 00000001 fff00006 00050001 00000001 00000094 00000001 fff00006 00050001 00000001 00000098 00000001 fff00006 00050001 00000001 0000009c 00000001 fff00006 00050001 00000001 000000a0 00000001 fff00006 00050001 00000001 000000a4 00000001 fff00006 
-
-
-
-Retreived T
-treeSpec: 000f0002 00060001 00000008 00000007 00000001 00020002 babe0003 00080001 00000003 00000007 00000001 00000001 00000002 00020001 00020000 
-paramSpec: 00050001 00000001 00010000 00000001 fff00006 00050001 00000001 00020000 00000001 fff00006 
-^C
- */
-
-//#include <iostream>
 #include <stdio.h>
 #include <time.h>
 #include <assert.h>
@@ -38,35 +25,14 @@ paramSpec: 00050001 00000001 00010000 00
 #include <NdbApi.hpp>
 #include <NdbSleep.h>
 #include <HugoOperations.hpp>
+#include <../../src/ndbapi/API.hpp>
+#include <../../src/ndbapi/NdbApiSignal.hpp>
+#include <kernel/signaldata/ScanTab.hpp>
 #include <kernel/signaldata/QueryTree.hpp>
 #include <kernel/AttributeHeader.hpp>
-#include <NdbQueryOperation.hpp>
-#include <NdbQueryBuilder.hpp>
-// 'impl' classes is needed for prototype only.
-//#include <NdbQueryOperationImpl.hpp>
-//#include "NdbQueryBuilderImpl.hpp"
 
 
 typedef uchar* gptr;
-static Uint32 storeCompactList(Uint32 * dst, const Vector<Uint32> & src);
-
-static void
-push_back(Vector<Uint32>& dst, const Uint32 * src, Uint32 len)
-{
-  for (Uint32 i = 0; i < len; i++)
-    dst.push_back(src[i]);
-}
-
-static void
-dump(const char * head, const Vector<Uint32> & src, const char * tail = 0)
-{
-  if (head)
-    printf("%s", head);
-  for (Uint32 i = 0; i<src.size(); i++)
-    printf("%.8x ", src[i]);
-  if (tail)
-    printf("%s", tail);
-}
 
 static int _scan = 0;
 static const char* _dbname = "TEST_DB";
@@ -83,166 +49,34 @@ static struct my_option my_long_options[
   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 };
 
-class ha_ndbcluster
-{
-public:
-  static Uint32 getTransPtr(NdbTransaction* trans){
-    return trans->theTCConPtr;
-  }
-};
-
-#ifdef UNUSED
 class NdbScanFilterImpl
 {
 public:
-  static void add(NdbOperation* op, const Uint32 * src, Uint32 len) {
-    op->insertATTRINFOloop(src, len);
-  }
-  static void add2(NdbScanOperation* op, const Uint32 * src, Uint32 len) {
-    op->insertATTRINFOData_NdbRecord((const char*)src, 4*len);
-  }
-  static void setIsLinkedFlag(NdbOperation* op){
-    op->m_isLinked = true;
-  }
-  static Uint32 getOpPtr(const NdbOperation* op, int recNo=0){
-    return op->ptr2int();
-  }
-  static Uint32 getTransPtr(NdbScanOperation* op){
-    return ha_ndbcluster::getTransPtr(op->theNdbCon);
-  }
-};
-#endif
-
-class ResultSet{
-public:
-  ResultSet(NdbQueryOperation* op, const NdbDictionary::Table *pTab){
-    for(int i=0; i<attrCount; i++){
-      mRecAttrs[i] = op->getValue(pTab->getColumn(attrNames[i]));
-    }
-  }
+  
 
-  void print() const{
-    for(int i=0; i<attrCount; i++){
-      ndbout << attrNames[i] << "=" << mRecAttrs[i]->u_32_value() << endl;
-    }
+  static void set(NdbScanOperation* op, const Uint32 * src, Uint32 len) {
+    op->theTotalCurrAI_Len = 0;
+    op->attrInfoRemain = 0;
+    op->theFirstATTRINFO = 0;
+    op->insertATTRINFOData_NdbRecord((const char*)src, 4*len);
   }
-private:
-  static const int attrCount = 6;
-  static const char* const attrNames[attrCount];
-  const NdbRecAttr * mRecAttrs[attrCount];
-};
-
-
-const char* const ResultSet::attrNames[ResultSet::attrCount] = {
-  "a", "b", "a0", "b0", "c0" , "c1" 
-};
-
-class LookupOp{
-public:
-  explicit LookupOp(const NdbOperation* pOp,
-		    bool final,
-		    int nodeNo);
-  void serializeOp(Vector<Uint32>& vec) const;
-  void serializeParam(Vector<Uint32>& vec) const;
-  int getOpLen() const {return QueryNode::getLength(qn.len);}
-  int getParamLen() const {return QueryNodeParameters::getLength(p.len);}
-  void setResultData(Uint32 resultIVal){
-    p.resultData = resultIVal;
+  static void setIsLinkedFlag(NdbScanOperation* op){
+    ScanTabReq * req = (ScanTabReq*)(op->theSCAN_TABREQ->getDataPtrSend());
+    ScanTabReq::setViaSPJFlag(req->requestInfo, 1);
   }
-private:
-  union {
-    QN_LookupNode qn;
-    Uint32 queryData[25];
-  };
-  union {
-    QN_LookupParameters p;
-    Uint32 paramData[25];
-  };
 };
 
-LookupOp::LookupOp(const NdbOperation* pOp, 
-		   bool final, 
-		   int nodeNo){
-  const NdbDictionary::Table * const pTab = pOp->getTable();
-  qn.tableId = pTab->getObjectId();
-  qn.tableVersion = pTab->getObjectVersion();
-
-  Uint32 optPos = 0;
-  if(final){
-    qn.requestInfo = 0;
-  }else{
-    qn.requestInfo = DABits::NI_LINKED_ATTR;
-  }
-
-  if(nodeNo>0){
-    qn.requestInfo |= DABits::NI_HAS_PARENT | DABits::NI_KEY_LINKED;
-    Vector<Uint32> parent;
-    parent.push_back(nodeNo-1); // Number...
-    optPos = storeCompactList(qn.optional, parent);
-  }
-
-  Vector<Uint32> attrList;
-  // Projection for link from child...
-  attrList.push_back(2); // a0
-  attrList.push_back(3); // b0
-
-  if(nodeNo>0){
-    qn.optional[optPos++] = attrList.size(); // length of KeyPattern
-    for (Uint32 i = 1; i <= attrList.size(); i++){
-      qn.optional[optPos++] = QueryPattern::col(attrList.size()-i);// KeyPattern
-    }
-  }
-
-  if(!final){
-    optPos += storeCompactList(qn.optional+optPos, attrList);
-  }
-    
-  // Set length of qn1.
-  QueryNode::setOpLen(qn.len, QueryNode::QN_LOOKUP,
-		      QN_LookupNode::NodeSize + optPos);
-  
-  // Has projection for child op.
-  p.requestInfo = DABits::PI_ATTR_LIST;
-  // Define a receiver object for this op.
-  //p.resultData = NdbScanFilterImpl::getOpPtr(pOp, nodeNo);
-  //p1.resultData = 0x10000; // NdbScanFilterImpl::getOpPtr(pOp);
-  // Define a result projection to include *all* attributes.
-  p.optional[0] = 1; // Length of user projection
-  AttributeHeader::init(p.optional + 1, AttributeHeader::READ_ALL,
-			pTab->getNoOfColumns());
-  // Set length of oprional part (projection)
-  QueryNodeParameters::setOpLen(p.len, QueryNodeParameters::QN_LOOKUP, p.NodeSize + 2);
-}
-
-void LookupOp::serializeOp(Vector<Uint32>& vec) const{
-  push_back(vec, queryData, QueryNode::getLength(qn.len));
-}
-
-void LookupOp::serializeParam(Vector<Uint32>& vec) const{
-  push_back(vec, paramData, QueryNodeParameters::getLength(p.len));
-}
 
-
-
-
-
-#if 0
 /**
  * SQL:
- drop table if exists T;
- create table T (a int, b int, a0 int not null, b0 int not null,
- c0 int unsigned , c1 int unsigned , primary key(a,b))
- engine = ndb;
-
- insert into T values (1,1,3,11,1,1);
- insert into T values (11,3,4,5,1,1);
- insert into T values (5,4,1,1,1,1);
- insert into T values (5,255,1,1,1,1);
-
+ drop table if exists t1;
+ create table t1 (a int primary key, b int not null) engine = ndb;
+ insert into t1 values (1,2), (2,3), (3,1);
 */
 
 
-int spjTest(int argc, char** argv){
+int main(int argc, char** argv)
+{
   NDB_INIT(argv[0]);
 
   const char *load_default_groups[]= { "mysql_cluster",0 };
@@ -280,590 +114,233 @@ int spjTest(int argc, char** argv){
   if (pTab == 0)
   {
     ndbout_c("Failed to retreive table: \"%s\"", argv[0]);
+    exit(0);
   }
   else
   {
     ndbout_c("Retreived %s", argv[0]);
   }
 
-  if (_scan == 0)
+  const NdbDictionary::Index * pIdx = dict->getIndex("PRIMARY", argv[0]);
+  if (pIdx == 0)
   {
-#ifdef UNUSED
-    /**
-       SELECT t1.*, t2.*
-       FROM T t1 LEFT OUTER JOIN T t2 ON t2.a = t1.b0 AND t2.b = t1.a0
-       WHERE t1.a = 1 and t1.b = 1;
-
-       sh> test_spj T
-    */
-
-    //HugoOperations hugoOps(* pTab);
-    NdbTransaction* pTrans = MyNdb.startTransaction();
-    NdbOperation* pOp = pTrans->getNdbOperation(pTab);
-    pOp->readTuple(NdbOperation::LM_Dirty);
-    pOp->equal("a", 11);
-    pOp->equal("b", 3);
-
-    Vector<Uint32> treeSpec;
-    Vector<Uint32> paramSpec;
-
-    union {
-      QueryTree qt;
-      Uint32 _data3[1];
-    };
-    /*LookupOp look1(pOp, false, 0);
-      LookupOp look2(pOp, true, 1);*/
-
-    const int nNodes = 2;
-    LookupOp* node[nNodes];
-    int totLen = 0;
-    for(int i=0; i<nNodes; i++){
-      node[i] = new LookupOp(pOp, i==nNodes-1,i);
-      totLen += node[i]->getOpLen();
-    }
-
-    QueryTree::setCntLen(qt.cnt_len, nNodes,
-                         1 +
-                         totLen);
-
-    push_back(treeSpec, _data3, 1);
-    
-    NdbQuery& query = NdbQueryImpl::buildQuery(*pTrans)->getInterface();
-    NdbQueryOperation* const root 
-      = &NdbQueryOperationImpl::buildQueryOperation(query.getImpl(), 
-						   *pOp)->getInterface();
-    //query->getImpl().setRootOperation(root);
-    NdbQueryOperation* currOp = root;
-    const ResultSet* rSet[nNodes];
-    rSet[0] = new ResultSet(root, pTab);
-    node[0]->setResultData(root->getImpl().ptr2int());
-    for(int i=1; i<nNodes; i++){
-      NdbQueryOperation* newOp = 
-	&NdbQueryOperationImpl::buildQueryOperation(query.getImpl(), 
-						   *pOp)->getInterface();
-      assert(0);
-      //currOp->getImpl().addChild(*newOp);
-      currOp = newOp;
-      rSet[i] = new ResultSet(newOp, pTab);
-      node[i]->setResultData(newOp->getImpl().ptr2int());
-    }
-
-    for(int i=0; i<nNodes; i++){
-      node[i]->serializeOp(treeSpec);
-    }
-
-    dump("treeSpec: ", treeSpec, "\n");
-
-    for(int i=0; i<nNodes; i++){
-      node[i]->serializeParam(paramSpec);
-    }
-
-    dump("paramSpec: ", paramSpec, "\n");
-
-    NdbScanFilterImpl::add(pOp, treeSpec.getBase(), treeSpec.size());
-    NdbScanFilterImpl::add(pOp, paramSpec.getBase(), paramSpec.size());
-    NdbScanFilterImpl::setIsLinkedFlag(pOp);
-
-    query.getImpl().prepareSend();
-    // extern NdbQueryImpl* queryImpl; 
-    pOp->setQueryImpl(&query.getImpl());
-    pTrans->execute(NoCommit);
-    // queryImpl = NULL;
-    /*if (pTrans->getNdbError().classification == NdbError::NoDataFound){
-      ndbout << "No data found" << endl;
-    }else{
-      ndbout << "myRecAttrs[2]->u_32_value()=" 
-		<< myRecAttrs[2]->u_32_value() << endl;
-		}*/
-    for(int i=0; i<nNodes; i++){
-      rSet[i]->print();
-    }
-#endif
+    ndbout_c("Failed to retreive index PRIMARY for table: \"%s\"", argv[0]);
+    exit(0);
   }
-  else if (_scan != 0)
+  else
   {
-    /**
-       SELECT t1.*, t2.*
-       FROM T t1 LEFT OUTER JOIN T t2 ON t2.a = t1.b0 AND t2.b = t1.a0;
-
-       sh> test_spj -s T
-    */
-
-    
-    NdbTransaction* pTrans = MyNdb.startTransaction();
-    NdbScanOperation* pOp = pTrans->scanTable(pTab->getDefaultRecord(),
-                                              NdbOperation::LM_Dirty);
-    Vector<Uint32> treeSpec;
-    Vector<Uint32> paramSpec;
-    Vector<Uint32> attrList;
-
-    union {
-      QN_ScanFragNode qn1;
-      Uint32 _data1[25];
-    };
-    qn1.requestInfo = DABits::NI_LINKED_ATTR;
-    qn1.tableId = pTab->getObjectId();
-    qn1.tableVersion = pTab->getObjectVersion();
+    ndbout_c("Retreived index PRIMARY for table %s", argv[0]);
+  }
 
-    // Linked ATTR
+  NdbTransaction * pTrans = MyNdb.startTransaction();
+  NdbScanOperation * pOp = pTrans->scanTable(pTab->getDefaultRecord(), 
+                                             NdbOperation::LM_CommittedRead);
 #if 0
-    for (int i = 0; i<pTab->getNoOfColumns(); i++)
-    {
-      if (pTab->getColumn(i)->getPrimaryKey())
-      {
-        attrList.push_back(i);
-      }
-    }
+  /**
+   * select STRAIGHT_JOIN *
+   * from t1 join t1 as t2 
+   * where t2.a = t1.b and t1.b <= 100 and t2.b <= 3;
+   *
+   * - ScanFrag
+   * PI_ATTR_INTERPRET w/ values inlined
+   * - Lookup
+   * PI_ATTR_INTERPRET w/ values in subroutine section
+   */
+  Uint32 request[] = {
+    // pos: 0
+    0x000d0002,
+
+    // ScanFragNode
+    0x00050002, // type/len
+    0x00000010, // bits
+    0x00000007, // table id
+    0x00000001, // table version
+    0x00010001, // #cnt linked / [ attr-list ]
+
+    // LookupNode
+    0x00070001, // type/len
+    0x00000003, // bits
+    0x00000007, // table id
+    0x00000001, // table version
+    0x00000001, // parent list
+    0x00000001, // key pattern: #parameters/#len
+    0x00020000, // P_COL col = 0
+
+    // ScanFragParameters
+    0x000c0002, // type/len
+    0x00000009, // bits
+    0x10000018, // result data
+    0x00000005, // #len subroutine / #len interpreted program
+    0x00043017, // p0: BRANCH_ATTR_OP_COL | LE | OFFSET-JUMP
+    0x00010004, // p0: ATTRID / LEN of VALUE
+    0x00000064, // p1: VALUE (100)
+    0x00000012, // p2: EXIT_OK
+    0x03830013, // p3: EXIT_NOK
+    0x00000002, // len user projection
+    0xfff00002, // read all
+    0xffe90000, // read any value
+    
+    // LookupParameters
+    0x000d0001, // type/len
+    0x00000009, // bits
+    0x1000001c, // result data
+
+    0x00020004, // #len subroutine / #len interpreted program
+    0x0003301a, // p0: BRANCH_ATTR_OP_COL | LE | OFFSET-JUMP
+    0x00000000, // p0: param ref 0
+    0x00000012, // p1: EXIT_OK
+    0x03830013, // p2: EXIT_NOK
+    0x00000004, // param 0 header
+    0x00000003, // param 0 value (3)
+
+    0x00000002, // len user projection
+    0xfff00002, // read all
+    0xffe90000  // read any value
+  };
+#elif 0
+  /**
+   * EXECUTE ?1 = 3
+   *   select STRAIGHT_JOIN *
+   *   from t1 join t1 as t2 
+   *   where t2.a = t1.b and t1.b <= 100 and t2.b <= ?1;
+   *
+   * - ScanFrag
+   * PI_ATTR_INTERPRET w/ values inlined
+   * - Lookup
+   * NI_ATTR_INTERPRET
+   * NI_ATTR_PARAMS & PI_ATTR_PARAMS
+   */
+  Uint32 request[] = {
+    // pos: 0
+    0x000d0002,
+
+    // ScanFragNode
+    0x00050002, // type/len
+    0x00000010, // bits
+    0x00000007, // table id
+    0x00000001, // table version
+    0x00010001, // #cnt linked / [ attr-list ]
+
+    // LookupNode
+    0x000e0001, // type/len
+    DABits::NI_HAS_PARENT | DABits::NI_KEY_LINKED |
+    DABits::NI_ATTR_INTERPRET | DABits::NI_ATTR_PARAMS,
+    0x00000007, // table id
+    0x00000001, // table version
+    0x00000001, // parent list
+    0x00000001, // key pattern: #parameters/#len
+    0x00020000, // P_COL col = 0
+    0x00010004, // attrinfo pattern: #len-pattern / #len interpreted program
+    0x0003301a, // p0: BRANCH_ATTR_OP_COL_2 | LE | OFFSET-JUMP
+    0x00010000, // p0: attrid: 1 / program param 0
+    0x00000012, // p1: EXIT_OK
+    0x03830013, // p2: EXIT_NOK
+    0x00000001, // attr-param pattern: #parameters
+    0x00060000, // attr-param pattern: P_PARAM_WITH_HEADER col=0
+
+    // ScanFragParameters
+    0x000c0002, // type/len
+    0x00000009, // bits
+    0x10000018, // result data
+    0x00000005, // #len subroutine / #len interpreted program
+    0x00043017, // p0: BRANCH_ATTR_OP_COL | LE | OFFSET-JUMP
+    0x00010004, // p1: ATTRID / LEN of VALUE
+    0x00000064, // p2: VALUE (100)
+    0x00000012, // p3: EXIT_OK
+    0x03830013, // p4: EXIT_NOK
+    0x00000002, // len user projection
+    0xfff00002, // read all
+    0xffe90000, // read any value
+        
+    // LookupParameters
+    0x00080001, // type/len
+    DABits::PI_ATTR_LIST | DABits::PI_ATTR_PARAMS, // bits
+    0x1000001c, // result data
+    0x00000004, // Param 0 header
+    0x00000003, // Param 0 value
+    0x00000002, // len user projection
+    0xfff00002, // read all
+    0xffe90000  // read any value
+  };
 #else
-    attrList.push_back(2); // a0
-    attrList.push_back(3); // b0
+  /**
+   *
+   * select STRAIGHT_JOIN *
+   * from t1 join t1 as t2 
+   * where t2.a = t1.b and t1.b <= 100 and t2.b <= t1.b;
+   *
+   * - ScanFrag
+   * PI_ATTR_INTERPRET w/ values inlined
+   * - Lookup
+   * NI_ATTR_INTERPRET
+   * NI_ATTR_LINKED
+   */
+  Uint32 request[] = {
+    // pos: 0
+    0x000d0002,
+
+    // ScanFragNode
+    0x00050002, // type/len
+    0x00000010, // bits
+    0x00000007, // table id
+    0x00000001, // table version
+    0x00010001, // #cnt linked / [ attr-list ]
+
+    // LookupNode
+    0x000e0001, // type/len
+    DABits::NI_HAS_PARENT | DABits::NI_KEY_LINKED |
+    DABits::NI_ATTR_INTERPRET | DABits::NI_ATTR_LINKED,
+    0x00000007, // table id
+    0x00000001, // table version
+    0x00000001, // parent list
+    0x00000001, // key pattern: #parameters/#len
+    0x00020000, // P_COL col = 0
+    0x00010004, // attrinfo pattern: #len-pattern / #len interpreted program
+    0x0003301a, // p0: BRANCH_ATTR_OP_COL_2 | LE | OFFSET-JUMP
+    0x00010000, // p0: attrid: 1 / program param 0
+    0x00000012, // p1: EXIT_OK
+    0x03830013, // p2: EXIT_NOK
+    0x00000000, // attr-param pattern: #parameters
+    0x00070000, // attr-param pattern: P_ATTRINFO col=0
+
+    // ScanFragParameters
+    0x000c0002, // type/len
+    0x00000009, // bits
+    0x10000018, // result data
+    0x00000005, // #len subroutine / #len interpreted program
+    0x00043017, // p0: BRANCH_ATTR_OP_COL | LE | OFFSET-JUMP
+    0x00010004, // p1: ATTRID / LEN of VALUE
+    0x00000064, // p2: VALUE (100)
+    0x00000012, // p3: EXIT_OK
+    0x03830013, // p4: EXIT_NOK
+    0x00000002, // len user projection
+    0xfff00002, // read all
+    0xffe90000, // read any value
+        
+    // LookupParameters
+    0x00060001, // type/len
+    DABits::PI_ATTR_LIST, // bits
+    0x1000001c, // result data
+    0x00000002, // len user projection
+    0xfff00002, // read all
+    0xffe90000  // read any value
+  };
 #endif
+  Uint32 n0 = (request[1] >> 16);
+  Uint32 n1 = (request[1 + n0] >> 16);
+  request[0] = ((1 + n0 + n1) << 16) | 2;
+
+  request[1+2] = pTab->getObjectId();
+  request[1+3] = pTab->getObjectVersion();
+
+  request[1 + n0 + 2] = pTab->getObjectId();
+  request[1 + n0 + 3] = pTab->getObjectVersion();
+
+  NdbScanFilterImpl::setIsLinkedFlag(pOp);
+  NdbScanFilterImpl::set(pOp, request, NDB_ARRAY_SIZE(request));
+                         
+  pTrans->execute(NoCommit);
+  while (true) NdbSleep_SecSleep(1);
 
-    Uint32 len0 = storeCompactList(qn1.optional, attrList);
-    QueryNode::setOpLen(qn1.len, QueryNode::QN_SCAN_FRAG,
-                        QN_LookupNode::NodeSize + len0);
-
-    union {
-      QN_LookupParameters p1;
-      Uint32 _data4[25];
-    };
-    p1.requestInfo = DABits::PI_ATTR_LIST;
-    p1.resultData = 0x10000; //NdbScanFilterImpl::getTransPtr(pOp);
-    p1.optional[0] = 2; // Length of user projecttion
-    AttributeHeader::init(p1.optional + 1, AttributeHeader::READ_ALL,
-                          pTab->getNoOfColumns());
-    /**
-     * correlation value
-     */
-    AttributeHeader::init(p1.optional + 2, AttributeHeader::READ_ANY_VALUE,
-                          0);
-    QueryNodeParameters::setOpLen(p1.len, QueryNodeParameters::QN_SCAN_FRAG, p1.NodeSize + 3);
-
-
-    union {
-      QN_LookupNode qn2;
-      Uint32 _data2[25];
-    };
-    qn2.requestInfo = DABits::NI_HAS_PARENT | DABits::NI_KEY_LINKED;
-    qn2.tableId = pTab->getObjectId();
-    qn2.tableVersion = pTab->getObjectVersion();
-    Vector<Uint32> parent;
-    parent.push_back(0); // Number...
-    Uint32 len1 = storeCompactList(qn2.optional, parent);
-    qn2.optional[len1] = attrList.size(); // length of KeyPattern
-    for (Uint32 i = 1; i <= attrList.size(); i++)
-      qn2.optional[len1+i] = QueryPattern::col(attrList.size()-i);// KeyPattern
-
-    QueryNode::setOpLen(qn2.len, QueryNode::QN_LOOKUP,
-                        QN_LookupNode::NodeSize + len1 + 1 + attrList.size());
-
-    union {
-      QN_LookupParameters p2;
-      Uint32 _data5[25];
-    };
-    p2.requestInfo = DABits::PI_ATTR_LIST;
-    p2.resultData = 0x20000; //NdbScanFilterImpl::getTransPtr(pOp);
-    p2.optional[0] = 2; // Length of user projection
-    AttributeHeader::init(p2.optional+1, AttributeHeader::READ_ALL,
-                          pTab->getNoOfColumns());
-    /**
-     * correlation value
-     */
-    AttributeHeader::init(p2.optional+2, AttributeHeader::READ_ANY_VALUE, 0);
-    QueryNodeParameters::setOpLen(p2.len, QueryNodeParameters::QN_LOOKUP, p2.NodeSize + 3);
-
-
-    union {
-      QueryTree qt;
-      Uint32 _data3[1];
-    };
-    QueryTree::setCntLen(qt.cnt_len, 2,
-                         1 +
-                         QueryNode::getLength(qn1.len) +
-                         QueryNode::getLength(qn2.len));
-
-    push_back(treeSpec, _data3, 1);
-    push_back(treeSpec, _data1, QueryNode::getLength(qn1.len));
-    push_back(treeSpec, _data2, QueryNode::getLength(qn2.len));
-
-    dump("treeSpec: ", treeSpec, "\n");
-
-    push_back(paramSpec, _data4, QueryNodeParameters::getLength(p1.len));
-    push_back(paramSpec, _data5, QueryNodeParameters::getLength(p2.len));
-
-    dump("paramSpec: ", paramSpec, "\n");
-
-    NdbScanFilterImpl::add2(pOp, treeSpec.getBase(), treeSpec.size());
-    NdbScanFilterImpl::add2(pOp, paramSpec.getBase(), paramSpec.size());
-    NdbScanFilterImpl::setIsLinkedFlag(pOp);
-
-    pTrans->execute(NoCommit);
-    while (true) NdbSleep_SecSleep(1);
-    while (pOp->nextResult() == 0);
-  }
   return NDBT_ProgramExit(NDBT_OK);
 }
-#endif
-
-
-/**
- * Helper debugging macros
- */
-/*#define PRINT_ERROR(code,msg)					 \
-  std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
-            << ", code: " << code \
-            << ", msg: " << msg << "." << std::endl*/
-#define PRINT_ERROR(code,msg) \
-  fprintf(stdout, "Error in %s, line: %d, code: %d, msg: %s.\n", \
-	  __FILE__, __LINE__, code, msg); 
-#define MYSQLERROR(mysql) { \
-  PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
-  exit(-1); }
-#define APIERROR(error) { \
-  PRINT_ERROR((error).code,(error).message); \
-  exit(-1); }
-
-
-int plainScan(int argc, char** argv){
-  NDB_INIT(argv[0]);
-
-  const char *load_default_groups[]= { "mysql_cluster",0 };
-  load_defaults("my",load_default_groups,&argc,&argv);
-  int ho_error;
-#ifndef DBUG_OFF
-  opt_debug= "d:t:O,/tmp/ndb_desc.trace";
-#endif
-  if ((ho_error=handle_options(&argc, &argv, my_long_options,
-			       ndb_std_get_one_option)))
-    return NDBT_ProgramExit(NDBT_WRONGARGS);
-
-  Ndb_cluster_connection con(opt_connect_str);
-  if(con.connect(12, 5, 1) != 0)
-  {
-    ndbout << "Unable to connect to management server." << endl;
-    return NDBT_ProgramExit(NDBT_FAILED);
-  }
-
-  int res = con.wait_until_ready(30,30);
-  if (res != 0)
-  {
-    ndbout << "Cluster nodes not ready in 30 seconds." << endl;
-    return NDBT_ProgramExit(NDBT_FAILED);
-  }
-
-  Ndb myNdb(&con, _dbname);
-  if(myNdb.init() != 0){
-    ERR(myNdb.getNdbError());
-    return NDBT_ProgramExit(NDBT_FAILED);
-  }
-
-  NdbDictionary::Dictionary*  const myDict = myNdb.getDictionary();
-  const NdbDictionary::Table* const tab = myDict->getTable("T");
-
-  assert(tab!=NULL);
-  
-  //APIERROR(myDict->getNdbError());
-  
-  NdbTransaction* myTransaction= myNdb.startTransaction();
-
-  NdbScanOperation* const scanOp = myTransaction->getNdbScanOperation(tab);
-  Uint32 results[6] = {0};
-  for(Uint32 i = 0; i<6; i++){
-    scanOp->getValue(i, reinterpret_cast<char*>(&results[i]));
-  }
-  
-  assert(myTransaction->execute(NoCommit)==0);
-  bool done = false;
-  while(!done){
-    switch(scanOp->nextResult(true, false)){
-    case 0:
-      for(Uint32 i = 0; i<6; i++){
-        ndbout << results[i] << " ";
-      }
-      ndbout << endl;
-      break;
-    case 1:
-      done = true;
-      break;
-    default:
-      assert(0);
-    }
-  }
-  return 0;
-}; // plainScan()
-
-
-
-int testSerialize(bool scan, int argc, char** argv){
-  NDB_INIT(argv[0]);
-
-  const char *load_default_groups[]= { "mysql_cluster",0 };
-  load_defaults("my",load_default_groups,&argc,&argv);
-  int ho_error;
-#ifndef DBUG_OFF
-  opt_debug= "d:t:O,/tmp/ndb_desc.trace";
-#endif
-  if ((ho_error=handle_options(&argc, &argv, my_long_options,
-			       ndb_std_get_one_option)))
-    return NDBT_ProgramExit(NDBT_WRONGARGS);
-
-  Ndb_cluster_connection con(opt_connect_str);
-  if(con.connect(12, 5, 1) != 0)
-  {
-    ndbout << "Unable to connect to management server." << endl;
-    return NDBT_ProgramExit(NDBT_FAILED);
-  }
-
-  int res = con.wait_until_ready(30,30);
-  if (res != 0)
-  {
-    ndbout << "Cluster nodes not ready in 30 seconds." << endl;
-    return NDBT_ProgramExit(NDBT_FAILED);
-  }
-
-  Ndb myNdb(&con, _dbname);
-  if(myNdb.init() != 0){
-    ERR(myNdb.getNdbError());
-    return NDBT_ProgramExit(NDBT_FAILED);
-  }
-
-  NdbDictionary::Dictionary*  const myDict = myNdb.getDictionary();
-  const NdbDictionary::Table* const tab = myDict->getTable("T");
-
-  if (tab==NULL) 
-    APIERROR(myDict->getNdbError());
-
-  NdbQueryBuilder myBuilder(myNdb);
-
-  NdbQueryBuilder* qb = &myBuilder; //myDict->getQueryBuilder();
-
-  if(scan){
-    struct ResRec{
-      char nullMap;
-      Uint32 values[6];
-    };
-
-    NdbDictionary::RecordSpecification spec[6];
-    for(int i = 0; i<6; i++){
-      spec[i].column= tab->getColumn(i);
-      spec[i].offset= offsetof(ResRec, values) + sizeof(Uint32)*i;
-      spec[i].nullbit_byte_offset= offsetof(ResRec, nullMap);
-      spec[i].nullbit_bit_in_byte= i;
-    }
-    const NdbRecord *resultRec =
-      myDict->createRecord(tab, spec, 6, sizeof(spec[0]));
-
-    //const NdbRecord* resultRec = tab->getDefaultRecord();
-    assert(resultRec!=NULL);
-    const NdbQueryScanOperationDef* scanOpDef = qb->scanTable(tab);
-    const NdbQueryOperand* linkKey[] = 
-      {  qb->linkedValue(scanOpDef, "b0"),
-         qb->linkedValue(scanOpDef, "a0"),
-         0
-      };
-    const NdbQueryLookupOperationDef* readLinked = qb->readTuple(tab, linkKey);
-    if (readLinked == NULL) APIERROR(qb->getNdbError());
-    const NdbQueryDef* const scanDef = qb->prepare();
-    NdbTransaction* myTransaction= myNdb.startTransaction();
-    const void* params[] = {NULL};
-    // Instantiate NdbQuery for this transaction.
-    NdbQuery* query = myTransaction->createQuery(scanDef, params);
-    //const Uint32* scanResultPtr;
-    //const unsigned char* mask = NULL;
-    NdbQueryOperation* const scanOp = query->getQueryOperation(0U);
-    /*scanOp->setResultRowRef(resultRec, 
-                        reinterpret_cast<const char*&>(scanResultPtr),
-                        NULL);*/
-    Uint32 scanResultPtr[6] = {0};
-    const NdbRecAttr* recAttrs[6] = {NULL};
-    for(Uint32 i = 0; i<6; i++){
-      recAttrs[i] 
-        = scanOp->getValue(i, reinterpret_cast<char*>(scanResultPtr+i));
-      assert(recAttrs[i]!=NULL);
-    }
-    const ResRec* lookupResultPtr;
-    NdbQueryOperation* const lookupOp = query->getQueryOperation(1);
-    lookupOp->setResultRowRef(resultRec, 
-                              reinterpret_cast<const char*&>(lookupResultPtr),
-                              NULL);
-    //extern bool stopHere;
-    //stopHere = true;
-    assert(myTransaction->execute(NoCommit)==0);
-    /*
-    while(!(scanOp->getImpl().isBatchComplete())){
-      sleep(1);
-      }*/
-    bool done = false;
-    int rowNo = 0;
-    while(!done){
-      // scanResultPtr = reinterpret_cast<char*>(results[rowNo]);
-      const int retVal = query->nextResult(true, false);
-      switch(retVal){
-      case 0:
-        break;
-      case 1:
-        done = true;
-        break;
-      case 2:
-        ndbout << "No more results in buffer";
-        done = true;
-        break;
-      default:
-        assert(false);
-      };
-      if(!done){
-        ndbout << "Scan row: " << rowNo << endl;
-        for(int i = 0; i<6; i++){
-          if(recAttrs[i]->isNULL()){
-            ndbout << "NULL ";
-          }else{
-            ndbout << scanResultPtr[i] << " ";
-          }
-        }
-        ndbout << endl;
-        ndbout << "Loopkup row: " << rowNo << endl;
-        if(lookupOp->isRowNULL()){
-          ndbout << "NULL" << endl;
-        }else{
-          for(int i = 0; i<6; i++){
-            if((lookupResultPtr->nullMap>>i) == 1){
-              ndbout << "NULL ";
-            }else{
-              ndbout << lookupResultPtr->values[i] << " ";
-            }
-          }
-          ndbout << endl;
-        }
-        rowNo++;
-      }
-    }
-  }else{
-    /* Dummy for now at least. Key is really set with  ndbOperation->equal().*/
-    const NdbQueryOperand* rootKey[] = 
-      {  qb->constValue(11), //a
-         //       qb->constValue(3), // b
-         qb->paramValue(),
-         0
-      };
-    // Lookup a 'root' tuple.
-    const NdbQueryLookupOperationDef *readRoot = qb->readTuple(tab, rootKey);
-    if (readRoot == NULL) APIERROR(qb->getNdbError());
-
-    /* Link to another lookup on the same table: 
-       WHERE tup1.a = tup0.b0 AND tup1.b = tup0.a0
-    */
-    const NdbQueryOperand* linkKey[] = 
-      {  qb->linkedValue(readRoot, "b0"),
-         qb->constValue(255), // b
-         // qb->linkedValue(readRoot, "a0"),
-         0
-      };
-    const NdbQueryLookupOperationDef* readLinked = qb->readTuple(tab, linkKey);
-    if (readLinked == NULL) APIERROR(qb->getNdbError());
-
-    const NdbQueryDef* queryDef = qb->prepare();
-    if (queryDef == NULL) APIERROR(qb->getNdbError());
-
-    assert (queryDef->getNoOfOperations() == 2);
-    assert (queryDef->getQueryOperation((Uint32)0) == readRoot);
-    assert (queryDef->getQueryOperation((Uint32)1) == readLinked);
-    assert (queryDef->getQueryOperation((Uint32)0)->getNoOfParentOperations() 
-            == 0);
-    assert (queryDef->getQueryOperation((Uint32)0)->getNoOfChildOperations() 
-            == 1);
-    assert (queryDef->getQueryOperation((Uint32)0)->getChildOperation((Uint32)0) 
-            == readLinked);
-    assert (queryDef->getQueryOperation((Uint32)1)->getNoOfParentOperations() 
-            == 1);
-    assert (queryDef->getQueryOperation((Uint32)1)->getParentOperation((Uint32)0) 
-            == readRoot);
-    assert (queryDef->getQueryOperation((Uint32)1)->getNoOfChildOperations() 
-            == 0);
-
-    //HugoOperations hugoOps(* tab);
-    NdbTransaction* myTransaction= myNdb.startTransaction();
-    if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
-
-    //NdbOperation* ndbOperation = myTransaction->getNdbOperation(tab);
-    const int bParam = 3;
-    const void* params[] = {&bParam, NULL};
-    // Instantiate NdbQuery for this transaction.
-    NdbQuery* query = myTransaction->createQuery(queryDef, params);
-
-    /* Read all attributes from result tuples.*/
-    const Uint32 opCount = query->getNoOfOperations();
-    const Uint32 recordOpCount = 0;
-    const ResultSet** resultSet = new const ResultSet*[opCount-recordOpCount];
-    for(Uint32 i = 0; i < opCount-recordOpCount; i++){
-      resultSet[i] 
-        = new ResultSet(query->getQueryOperation(recordOpCount+i), tab);
-    }
-    const NdbRecord* resultRec = tab->getDefaultRecord();
-    assert(resultRec!=NULL);
-    Uint32 results[2][6] = {0U};
-    const unsigned char mask[] = {0xe};
-    for(Uint32 i = 0; i<recordOpCount; i++){
-      for(Uint32 j = 0; j<6; j++){
-        results[i][j]= 0x0;
-      }
-    }
-    for(Uint32 i = 0; i<recordOpCount; i++){
-      const int error = query->getQueryOperation(i)
-        ->setResultRowBuf(resultRec, 
-                          reinterpret_cast<char*>(results[i]), NULL);
-      assert(error==0);
-    }
-    myTransaction->execute(NoCommit);
-    assert(query->nextResult(true, false)==0);
-    for(Uint32 i = 0; i<recordOpCount; i++){
-      for(int j = 0; j<6; j++){
-        ndbout << results[i][j] << " ";
-      }
-      ndbout << endl;
-    }
-    // Print results.
-    for(Uint32 i=0; i < opCount-recordOpCount; i++){
-      resultSet[i]->print();
-    }
-    assert(query->nextResult(false, false)==2);
-    assert(query->nextResult(true, false)==1);
-  }
-  return 0;
-};
-
-
-int main(int argc, char** argv){
-  //plainScan(argc, argv)
-  testSerialize(false, argc, argv);
-  testSerialize(true, argc, argv);
-  return 0;
-}
-/**
- * Store list of 16-bit integers put into 32-bit integers
- * adding a count as first 16-bit
- */
-static
-Uint32
-storeCompactList(Uint32 * dst, const Vector<Uint32> & src)
-{
-  Uint32 cnt = src.size();
-  if (cnt)
-  {
-    dst[0] = cnt | (src[0] << 16);
-    for (Uint32 i = 1; i+1 < cnt; i += 2)
-    {
-      dst[1 + (i - 1)/2] = src[i] | (src[i+1] << 16);
-    }
-    Uint32 len = 1 + (cnt - 1) / 2;
-    if ((cnt & 1) == 0)
-    {
-      dst[len++] = src[cnt-1] | (0xBABE << 16);
-    }
-
-    return len;
-  }
-
-  return 0;
-}
-
-template class Vector<Uint32>;


Attachment: [text/bzr-bundle] bzr/jonas@mysql.com-20100430110317-am8eld4lclx0b2ql.bundle
Thread
bzr commit into mysql-5.1-telco-7.0-spj branch (jonas:3145)Jonas Oreland30 Apr