List:Commits« Previous MessageNext Message »
From:Jan Wedvik Date:July 24 2009 8:55am
Subject:bzr commit into mysql-5.1-telco-7.0-spj branch (jan.wedvik:2936)
View as plain text  
#At file:///export/home2/tmp/jw1159207/mysql/mysql-5.1-telco-7.0-spj/ based on revid:jan.wedvik@stripped

 2936 Jan Wedvik	2009-07-24 [merge]
      Merged from bk-internal.mysql.com/bzrroot/server/mysql-5.1-telco-7.0-spj/ branch.

    modified:
      storage/ndb/ndbapi-examples/ndbapi_multi_cursor/main.cpp
      storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp
      storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp
      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/Ndbif.cpp
=== modified file 'storage/ndb/ndbapi-examples/ndbapi_multi_cursor/main.cpp'
--- a/storage/ndb/ndbapi-examples/ndbapi_multi_cursor/main.cpp	2009-07-13 11:15:51 +0000
+++ b/storage/ndb/ndbapi-examples/ndbapi_multi_cursor/main.cpp	2009-07-24 08:55:33 +0000
@@ -53,7 +53,7 @@
 /**
  * Define NDB_CONNECT_STRING if you don't connect through the default localhost:1186
  */
-  #define NDB_CONNECT_STRING "loki43:2360"
+  #define NDB_CONNECT_STRING "127.0.0.1:2360"
 
 
 /*****************************************************
@@ -89,6 +89,7 @@ struct SalaryRow
 const char* employeeDef = 
 "CREATE TABLE employees ("
 "    emp_no      INT             NOT NULL,"
+"    dept_no     INT         NOT NULL,"   // Temporary added OJA
 "    birth_date  DATE            NOT NULL,"
 "    first_name  VARCHAR(14)     NOT NULL,"
 "    last_name   VARCHAR(16)     NOT NULL,"
@@ -107,7 +108,7 @@ const char* departmentsDef = 
 
 const char* dept_managerDef = 
 "CREATE TABLE dept_manager ("
-"   dept_no      CHAR(4)         NOT NULL,"
+"   dept_no      INT         NOT NULL,"
 "   emp_no       INT             NOT NULL,"
 "   from_date    DATE            NOT NULL,"
 "   to_date      DATE            NOT NULL,"
@@ -169,7 +170,7 @@ int createEmployeeDb()
 //    mysql_options(&mysql, MYSQL_READ_DEFAULT_FILE, "/home/oa136780/mysql/mysql-5.1-telco-7.0-spj/install/config/my.cnf");
 
     const char *mysqld_sock = "/tmp/mysql.sock";
-    if ( !mysql_real_connect(&mysql, "loki43", "root", "", "",
+    if ( !mysql_real_connect(&mysql, "127.0.0.1", "root", "", "",
 			     4401, NULL, 0) )
       return 0;
 
@@ -208,13 +209,27 @@ int createEmployeeDb()
     mysql_commit(&mysql);
     printf("Created 'salaries' table\n");
 
+
+
+    /****
     printf("Insert simple test data\n");
-    if (mysql_query(&mysql, "Insert into dept_manager(dept_no,emp_no) values ('d005', 110567)") != 0) MYSQLERROR(mysql);
+    if (mysql_query(&mysql, "Insert into dept_manager(dept_no,emp_no) values ('d005',110567)") != 0) MYSQLERROR(mysql);
+    mysql_commit(&mysql);
+
+    if (mysql_query(&mysql, "Insert into employees(emp_no,dept_no) values (110567,'d005')") != 0) MYSQLERROR(mysql);
+    mysql_commit(&mysql);
+    ******/
+
+    /********/
+   printf("Insert simple test data\n");
+    if (mysql_query(&mysql, "Insert into dept_manager(dept_no,emp_no) values (1005,110567)") != 0) MYSQLERROR(mysql);
     mysql_commit(&mysql);
 
-    if (mysql_query(&mysql, "Insert into employees(emp_no) values (110567)") != 0) MYSQLERROR(mysql);
+    if (mysql_query(&mysql, "Insert into employees(emp_no,dept_no) values (110567,1005)") != 0) MYSQLERROR(mysql);
     mysql_commit(&mysql);
 
+    /************/
+
     mysql_close(&mysql);
   }
 
@@ -266,6 +281,9 @@ static void init_ndbrecord_info(Ndb &myN
 int testQueryBuilder(Ndb &myNdb)
 {
   const NdbDictionary::Table *manager, *employee, *salary;
+  int res;
+  NdbTransaction* myTransaction;
+  NdbQuery* myQuery;
 
   printf("\n -- Building query --\n");
 
@@ -289,6 +307,7 @@ int testQueryBuilder(Ndb &myNdb)
    */
   NdbQueryBuilder myBuilder(myNdb);
 
+#if 0
   /* qt1 is 'const defined' */
   printf("q1\n");
   const NdbQueryDef* q1 = 0;
@@ -350,7 +369,6 @@ int testQueryBuilder(Ndb &myNdb)
   }
 *****/
 
-
   /* Composite operations building real *trees* aka. linked operations.
    * (First part is identical to building 'qt2' above)
    *
@@ -382,17 +400,18 @@ int testQueryBuilder(Ndb &myNdb)
     //    A linked value is used to let employee lookup refer values
     //    from the parent operation on manger.
 
-    const NdbQueryOperand* empJoinKey[] =       // Employee is indexed om {"emp_no"}
+    const NdbQueryOperand* joinEmployeeKey[] =       // Employee is indexed om {"emp_no"}
     {  qb->linkedValue(readManager, "emp_no"),  // where '= readManger.emp_no'
        0
     };
-    const NdbQueryLookupOperationDef* readEmployee = qb->readTuple(employee, empJoinKey);
+    const NdbQueryLookupOperationDef* readEmployee = qb->readTuple(employee, joinEmployeeKey);
     if (readEmployee == NULL) APIERROR(qb->getNdbError());
 
     q4 = qb->prepare();
     if (q4 == NULL) APIERROR(qb->getNdbError());
   }
 
+
   ///////////////////////////////////////////////////
   // q4 may later be executed as:
   // (Possibly multiple ::execute() or multiple NdbQueryDef instances 
@@ -402,17 +421,13 @@ int testQueryBuilder(Ndb &myNdb)
   Uint32 emp_no = 110567;
   void* paramList[] = {&dept_no, &emp_no};
 
-  NdbTransaction* myTransaction= myNdb.startTransaction();
+  myTransaction= myNdb.startTransaction();
   if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
 
-  NdbQuery* myQuery = myTransaction->createQuery(q4, paramList);
+  myQuery = myTransaction->createQuery(q4,0); // paramList);
   if (myQuery == NULL)
     APIERROR(myTransaction->getNdbError());
 
-  // TEMP HACK: Set keys for root lookup.
-  myQuery->getImpl().getNdbOperation()->equal("dept_no", "d005");
-  myQuery->getImpl().getNdbOperation()->equal("emp_no",   110567);
-
 #if 0
   ManagerRow managerRow;
   memset (&managerRow, 0, sizeof(managerRow));
@@ -435,11 +450,6 @@ int testQueryBuilder(Ndb &myNdb)
 
     key[i][0] =  op->getValue(table->getColumn(0));
     key[i][1] =  op->getValue(table->getColumn(1));
-
-    for (Uint32 col=2; col<table->getNoOfColumns(); col++)
-    {
-      op->getValue(table->getColumn(col));
-    }
   }
 #endif
 
@@ -450,7 +460,7 @@ int testQueryBuilder(Ndb &myNdb)
 
   // All NdbQuery operations are handled as scans with cursor placed 'before'
   // first record: Fetch next to retrieve result:
-  int res = myQuery->nextResult();
+  res = myQuery->nextResult();
   if (res == -1)
     APIERROR(myQuery->getNdbError());
 
@@ -461,6 +471,92 @@ int testQueryBuilder(Ndb &myNdb)
 
   myNdb.closeTransaction(myTransaction);
   myTransaction = 0;
+#endif
+
+  //////////////////////////////////////////////////
+  printf("q4_1\n");
+  const NdbQueryDef* q4_1 = 0;
+  {
+    NdbQueryBuilder* qb = &myBuilder; //myDict->getQueryBuilder();
+
+    const NdbQueryOperand* constEmpKey[] =       // Employee is indexed om {"emp_no"}
+    {  qb->constValue(110567),   // emp_no  = 110567
+       0
+    };
+    const NdbQueryLookupOperationDef* readEmployee = qb->readTuple(employee, constEmpKey);
+    if (readEmployee == NULL) APIERROR(qb->getNdbError());
+
+    const NdbQueryOperand* joinManagerKey[] =  // Manager is indexed om {"dept_no", "emp_no"}
+    {
+      //qb->constValue(1005),   // dept_no = "d005"
+      qb->linkedValue(readEmployee,"dept_no"),
+      //qb->linkedValue(readEmployee,"emp_no"),   // emp_no  = 110567
+      qb->constValue(110567),
+      //qb->paramValue(), //BEWARE: param serialization incomplete and will cause node failure!! 
+      0
+    };
+
+    // Join with a single tuple with key defined by linked employee fields
+    const NdbQueryLookupOperationDef *readManager = qb->readTuple(manager, joinManagerKey);
+    if (readManager == NULL) APIERROR(qb->getNdbError());
+
+    q4_1 = qb->prepare();
+    if (q4_1 == NULL) APIERROR(qb->getNdbError());
+  }
+
+  ///////////////////////////////////////////////////
+  // q4 may later be executed as:
+  // (Possibly multiple ::execute() or multiple NdbQueryDef instances 
+  // within the same NdbTransaction::execute(). )
+  ////////////////////////////////////////////////////
+  //char* dept_no = "d005";
+  Uint32 emp_no_q4 = 110567;
+  void* paramList_q4[] = {&emp_no_q4};
+
+  myTransaction= myNdb.startTransaction();
+  if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
+
+  myQuery = myTransaction->createQuery(q4_1,0); //paramList_q4);
+  if (myQuery == NULL)
+    APIERROR(myTransaction->getNdbError());
+
+  const NdbRecAttr *value_q4[2][2];
+
+  for (Uint32 i=0; i<myQuery->getNoOfOperations(); ++i)
+  {
+    NdbQueryOperation* op = myQuery->getQueryOperation(i);
+    const NdbDictionary::Table* table = op->getQueryOperationDef().getTable();
+
+    value_q4[i][0] =  op->getValue(table->getColumn(0));
+    value_q4[i][1] =  op->getValue(table->getColumn(1));
+  }
+
+  printf("Start execute\n");
+  if (myTransaction->execute( NdbTransaction::NoCommit ) == -1)
+    APIERROR(myTransaction->getNdbError());
+  printf("Done executed\n");
+
+  // All NdbQuery operations are handled as scans with cursor placed 'before'
+  // first record: Fetch next to retrieve result:
+  res = myQuery->nextResult();
+  if (res == -1)
+    APIERROR(myQuery->getNdbError());
+
+  printf("employee emp_no: %d\n", value_q4[0][0]->u_32_value());
+  printf("manager  emp_no: %d\n", value_q4[1][1]->u_32_value());
+
+  // NOW: Result is available in 'managerRow' buffer
+
+  myNdb.closeTransaction(myTransaction);
+  myTransaction = 0;
+
+
+
+  /////////////////////////////////////////////////
+
+
+
+#if 0
 
   // Example: ::readTuple() using Index for unique key lookup
   printf("q5\n");
@@ -517,23 +613,29 @@ int testQueryBuilder(Ndb &myNdb)
     const NdbQueryScanOperationDef* scanManager = qb->scanTable(manager);
     if (scanManager == NULL) APIERROR(qb->getNdbError());
 
+    // THEN: employee table is joined:
+    //    A linked value is used to let employee lookup refer values
+    //    from the parent operation on manager.
+
+    const NdbQueryOperand* empJoinKey[] =       // Employee is indexed om {"emp_no"}
+    {  qb->linkedValue(scanManager, "emp_no"),  // where '= readManger.emp_no'
+       0
+    };
+    const NdbQueryLookupOperationDef* readEmployee = qb->readTuple(employee, empJoinKey);
+    if (readEmployee == NULL) APIERROR(qb->getNdbError());
+
     q6 = qb->prepare();
     if (q6 == NULL) APIERROR(qb->getNdbError());
   }
 
+
   myTransaction= myNdb.startTransaction();
   if (myTransaction == NULL) APIERROR(myNdb.getNdbError());
 
-  myQuery = myTransaction->createQuery(q6, paramList);
+  myQuery = myTransaction->createQuery(q6, 0);
   if (myQuery == NULL)
     APIERROR(myTransaction->getNdbError());
 
-  // TEMP HACK: Set keys for root lookup.
-  // NOTE: There should not be any keys for table scans!
-  // However, index scans may have a 'prune key'
-//  myQuery->getImpl().getNdbOperation()->equal("dept_no", "d005");
-//  myQuery->getImpl().getNdbOperation()->equal("emp_no",   110567);
-
   const NdbRecAttr* value[2][2];
 
   for (Uint32 i=0; i<myQuery->getNoOfOperations(); ++i)
@@ -562,12 +664,14 @@ int testQueryBuilder(Ndb &myNdb)
     APIERROR(myQuery->getNdbError());
 
   printf("manager  emp_no: %d\n", value[0][1]->u_32_value());
-//printf("employee emp_no: %d\n", value[1][0]->u_32_value());
+  printf("employee emp_no: %d\n", value[1][0]->u_32_value());
 
   // NOW: Result is available in 'managerRow' buffer
 
   myNdb.closeTransaction(myTransaction);
   myTransaction = 0;
+#endif
+
 
   return 0;
 }

=== modified file 'storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp	2009-06-25 06:13:48 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp	2009-07-17 21:57:40 +0000
@@ -75,7 +75,7 @@ public:
    * This struct represent a row being passed to a child
    *   currently only the RT_SECTION type is supported
    *   but RT_ROW_BUF is also planned (for buffered rows)
-   *     that will be used for eqi-join (and increased parallelism on scans)
+   *     that will be used for equi-join (and increased parallelism on scans)
    */
   struct RowRef
   {
@@ -249,7 +249,7 @@ public:
 
   /**
    * A node in a Query
-   *   (This is is an instantiated version of QueryNode in
+   *   (This is an instantiated version of QueryNode in
    *    include/kernel/signal/QueryTree.hpp)
    */
   struct TreeNode

=== modified file 'storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp	2009-07-13 11:15:51 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp	2009-07-24 08:55:33 +0000
@@ -1347,6 +1347,8 @@ Dbspj::lookup_execLQHKEYREF(Signal* sign
     ref->errorCode = errCode;
     ref->errorData = 0;
 
+    DEBUG("lookup_execLQHKEYREF, errorCode:" << errCode);
+
     sendSignal(resultRef, GSN_TCKEYREF, signal,
                TcKeyRef::SignalLength, JBB);
   }
@@ -1397,13 +1399,15 @@ Dbspj::lookup_start_child(Signal* signal
   const Uint32 tableId = LqhKeyReq::getTableId(src->tableSchemaVersion);
   const Uint32 corrVal = rowRef.m_src_correlation;
 
+  DEBUG("::lookup_start_child");
+
   do
   {
     Uint32 ptrI = RNIL;
     if (treeNodePtr.p->m_bits & TreeNode::T_KEYINFO_CONSTRUCTED)
     {
       jam();
-
+      DEBUG("start_child w/ T_KEYINFO_CONSTRUCTED");
       /**
        * Get key-pattern
        */
@@ -1491,8 +1495,15 @@ Dbspj::getNodes(Signal* signal, BuildKey
   req->hashValue = dst.hashInfo[1];
   req->distr_key_indicator = 0; // userDefinedPartitioning not supported!
 
+#if 1
   EXECUTE_DIRECT(DBDIH, GSN_DIGETNODESREQ, signal,
                  DiGetNodesReq::SignalLength);
+#else
+  sendSignal(DBDIH_REF, GSN_DIGETNODESREQ, signal,
+             DiGetNodesReq::SignalLength, JBB);
+  jamEntry();
+
+#endif
 
   DiGetNodesConf * conf = (DiGetNodesConf *)&signal->theData[0];
   err = signal->theData[0];
@@ -1500,6 +1511,8 @@ Dbspj::getNodes(Signal* signal, BuildKey
   Uint32 nodeId = conf->nodes[0];
   Uint32 instanceKey = (Tdata2 >> 24) & 127;
 
+  DEBUG("HASH to nodeId:" << nodeId << ", instanceKey" << instanceKey);
+
   jamEntry();
   if (unlikely(err != 0))
     goto error;
@@ -2006,7 +2019,7 @@ Dbspj::buildRowHeader(RowRef::Header * h
 {
   Uint32 tmp, len;
   Uint32 * dst = (Uint32*)header->m_headers;
-  Uint32 * save = dst;
+  const Uint32 * save = dst;
   SectionReader r0(ptr, getSectionSegmentPool());
   do
   {
@@ -2026,11 +2039,12 @@ Uint32
 Dbspj::buildRowHeader(RowRef::Header * header, const Uint32 * src, Uint32 len)
 {
   Uint32 * dst = (Uint32*)header->m_headers;
-  Uint32 * save = dst;
+  const Uint32 * save = dst;
   for (Uint32 i = 0; i<len; i++)
   {
     Uint32 tmp = * src++;
     Uint32 tmp_len = AttributeHeader::getDataSize(tmp);
+    DEBUG("::buildRowHeader, tmp:" << tmp << ", tmp_len:" << tmp_len);
     * dst++ = tmp;
     src += tmp_len;
   }
@@ -2042,6 +2056,8 @@ Uint32
 Dbspj::appendToPattern(Local_pattern_store & pattern,
                        DABuffer & tree, Uint32 len)
 {
+  DEBUG("::appendToPattern, len:" << len);
+
   Uint32 err = DbspjErr::InvalidTreeNodeSpecification;
   if (tree.ptr + len <= tree.end)
   {
@@ -2119,6 +2135,8 @@ Dbspj::getColData32(const RowRef::Sectio
 Uint32
 Dbspj::appendColToSection(Uint32 & dst, const RowRef::Section & row, Uint32 col)
 {
+  DEBUG("::appendColToSection1, col:" << col);
+
   /**
    * TODO handle errors
    */
@@ -2140,6 +2158,8 @@ Dbspj::appendColToSection(Uint32 & dst, 
 Uint32
 Dbspj::appendColToSection(Uint32 & dst, const RowRef::Linear & row, Uint32 col)
 {
+  DEBUG("::appendColToSection2, col:" << col);
+
   /**
    * TODO handle errors
    */
@@ -2160,6 +2180,8 @@ Dbspj::appendDataToSection(Uint32 & ptrI
 			   Local_pattern_store::ConstDataBufferIterator& it,
 			   Uint32 len)
 {
+  DEBUG("::appendDataToSection, len:" << len);
+
 #if 0
   /**
    * TODO handle errors
@@ -2182,6 +2204,7 @@ Dbspj::appendDataToSection(Uint32 & ptrI
   
   while(remaining>0 && !it.isNull())
   {
+    DEBUG("  data:" << *it.data);
     tmp[dstIdx] = *it.data;
     remaining--;
     dstIdx++;
@@ -2236,23 +2259,31 @@ Uint32
 Dbspj::expand(Uint32 & _dst, Local_pattern_store& pattern,
               const RowRef::Section & row)
 {
+  DEBUG("::expand1");
+
   Uint32 err;
   Uint32 dst = _dst;
   Local_pattern_store::ConstDataBufferIterator it;
-  for (pattern.first(it); !it.isNull(); pattern.next(it))
+  pattern.first(it);
+  while (!it.isNull())
   {
     Uint32 info = *it.data;
     Uint32 type = QueryPattern::getType(info);
     Uint32 val = QueryPattern::getLength(info);
-    err = DbspjErr::InvalidPattern;
+    pattern.next(it);
+
     switch(type){
     case QueryPattern::P_COL:
+      DEBUG("  COL, val:" << val);
       err = appendColToSection(dst, row, val);
       break;
     case QueryPattern::P_DATA:
-      pattern.next(it);
+      DEBUG("  DATA, val:" << val);
       err = appendDataToSection(dst, pattern, it, val);
       break;
+    default:
+      err = DbspjErr::InvalidPattern;
+      DEBUG_CRASH();
     }
     if (unlikely(err != 0))
     {
@@ -2271,6 +2302,7 @@ Uint32
 Dbspj::expand(Uint32 & ptrI, DABuffer& pattern, Uint32 len,
               DABuffer& param, Uint32 cnt)
 {
+  DEBUG("::expand2, len:" << len << ", cnt:" << cnt);
   /**
    * TODO handle error
    */
@@ -2291,17 +2323,23 @@ Dbspj::expand(Uint32 & ptrI, DABuffer& p
     Uint32 info = * ptr++;
     Uint32 type = QueryPattern::getType(info);
     Uint32 val = QueryPattern::getLength(info);
-    err = DbspjErr::InvalidPattern;
     switch(type){
     case QueryPattern::P_COL:
+      DEBUG("  COL, val:" << val);
       err = appendColToSection(dst, row, val);
       break;
     case QueryPattern::P_DATA:
+      DEBUG("  DATA, val:" << val);
       if(likely(appendToSection(dst, ptr, val))){
 	err = 0;
+      } else {
+        err = DbspjErr::InvalidPattern;
       }
       ptr += val;
       break;
+    default:
+      err = DbspjErr::InvalidPattern;
+      DEBUG_CRASH();
     }
     if (unlikely(err != 0))
     {
@@ -2325,6 +2363,7 @@ Uint32
 Dbspj::expand(Local_pattern_store& dst, DABuffer& pattern, Uint32 len,
               DABuffer& param, Uint32 cnt)
 {
+  DEBUG("::expand3, len:" << len << ", cnt:" << cnt << ", param: @" << param.ptr);
   /**
    * TODO handle error
    */
@@ -2335,6 +2374,10 @@ Dbspj::expand(Local_pattern_store& dst, 
   row.m_header = (RowRef::Header*)tmp;
   row.m_data = param.ptr;
 
+  DEBUG("row.header.len:" << row.m_header->m_len);
+
+  DEBUG("(Param) row @" << param.ptr);
+
   const Uint32 * ptr = pattern.ptr;
   const Uint32 * end = ptr + len;
 
@@ -2343,15 +2386,19 @@ Dbspj::expand(Local_pattern_store& dst, 
     Uint32 info = * ptr++;
     Uint32 type = QueryPattern::getType(info);
     Uint32 val = QueryPattern::getLength(info);
-    err = DbspjErr::InvalidPattern;
     switch(type){
     case QueryPattern::P_COL:
+      DEBUG("  COL pattern, val:" << val);
       err = appendColToPattern(dst, row, val);
       break;
     case QueryPattern::P_DATA:
+      DEBUG("  DATA pattern, val:" << val);
       err = dst.append(ptr, val) ? 0 : DbspjErr::OutOfQueryMemory;
       ptr += val;
       break;
+    default:
+      err = DbspjErr::InvalidPattern;
+      DEBUG_CRASH();
     }
     if (unlikely(err != 0))
     {
@@ -2366,6 +2413,8 @@ Dbspj::expand(Local_pattern_store& dst, 
   pattern.ptr = end;
   param.ptr += row.m_header->m_len;
 
+  DEBUG("param end at" << param.ptr << ", row.header.len:" << row.m_header->m_len);
+
   return 0;
 
 error:
@@ -2431,7 +2480,7 @@ Dbspj::parseDA(Build_context& ctx,
 		    | DABits::NI_KEY_CONSTS))
     {
       jam();
-      DEBUG("NI_KEY_PARAMS | NI_KEY_LINKED");
+      DEBUG("NI_KEY_PARAMS | NI_KEY_LINKED | NI_KEY_CONSTS");
 
       /**
        * OPTIONAL PART 2:
@@ -2483,7 +2532,7 @@ Dbspj::parseDA(Build_context& ctx,
           treeNodePtr.p->m_send.m_keyInfoPtrI = keyInfoPtrI;
         }
       }
-      else
+      else  // cnt==0 -> No parameters in key (const + linked)
       {
         jam();
         DEBUG("KEY-PATTERN: len: " << len);
@@ -2492,6 +2541,9 @@ Dbspj::parseDA(Build_context& ctx,
          */
         ndbrequire((treeBits & DABits::NI_KEY_PARAMS) == 0);
         ndbrequire((paramBits & DABits::PI_KEY_PARAMS) == 0);
+
+        // FIXME: Key may contain *both* CONST, PARAM and LINKED KEY fields
+        //  .... which currently does not work...
         if((treeBits & DABits::NI_KEY_LINKED) == 0)
         {
           DEBUG("FIXED-CONST-KEY");
@@ -2501,14 +2553,16 @@ Dbspj::parseDA(Build_context& ctx,
            *   This means a "fixed" key from here on
            */
           Uint32 keyInfoPtrI = RNIL;
-          err = expand(keyInfoPtrI, tree, len, param, 0);
+          err = expand(keyInfoPtrI, tree, len, param, 0); // ... 'expand2'
           assert(err==0);
           treeNodePtr.p->m_send.m_keyInfoPtrI = keyInfoPtrI;
-	  
         }
 	else
         {
-          err = appendToPattern(pattern, tree, len);
+          DEBUG("LINKED-KEY");
+	  //err = expand(pattern, tree, len, param, cnt);
+
+	  err = appendToPattern(pattern, tree, len);
           /**
            * This node constructs a new key for each send
            */

=== modified file 'storage/ndb/src/ndbapi/NdbQueryBuilder.cpp'
--- a/storage/ndb/src/ndbapi/NdbQueryBuilder.cpp	2009-07-15 10:40:01 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryBuilder.cpp	2009-07-24 08:55:33 +0000
@@ -37,18 +37,13 @@
  * (Particular the ConstOperant in order to implement multiple datatypes)
  *
  * In order to avoid allocating both an interface object and its particular
- * Impl object, all 'final' Impl objects inherit its interface class.
- * As all 'Impl' object 'is a' interface object:
- *   - C++ auto downcasting may be used to get the interface object.
- *   - Impl classes does not have to be friend of the interface classes.
+ * Impl object, all 'final' Impl objects contains a m_interface object with 
+ * the type of its interface class.
+ * All 'Impl' object 'has a' interface object which is accessible through
+ * the virtual method ::getInterface.
  *
- * ::getImpl() functions has been defined for convenient access 
- * to all available interface classes.
- *
- * CODE STATUS:
- *   Except for creating the Query objects, the NdbQueryBuilder factory
- *   does not do any usefull work yet. This is a framework for further
- *   logic to be added.
+ * ::getImpl() methods has been defined for convenient access 
+ * to all available Impl classes.
  * 
  */
 
@@ -73,162 +68,20 @@ setErrorCode(NdbQueryBuilder* qb, int aE
     return NULL;			\
   }
 
-/** The type of an operand. This corresponds to the set of subclasses
- * of NdbQueryOperand.*/
-enum OperandKind{
-  OperandKind_Linked,
-  OperandKind_Param,
-  OperandKind_Const
-};
 
 //////////////////////////////////////////////
 // Implementation of NdbQueryOperand interface
-//////////////////////////////////////////////
-
-
-// Baseclass for the QueryOperand implementation
-class NdbQueryOperandImpl
-{
-public:
-  const NdbDictionary::Column* getColumn() const
-  { return m_column; };
-
-  virtual int bindOperand(const NdbDictionary::Column& column,
-                          NdbQueryOperationDefImpl& operation)
-  { if (m_column  && m_column != &column)
-      // Already bounded to a different column
-      return QRY_OPERAND_ALREADY_BOUND;
-    m_column = &column;
-    return 0;
-  }
-  
-  virtual const NdbQueryOperand& getInterface() const = 0; 
-
-  OperandKind getKind() const
-  { return m_kind;
-  }
-protected:
-  virtual ~NdbQueryOperandImpl()=0;
-
-  NdbQueryOperandImpl(OperandKind kind)
-    : m_column(0),
-      m_kind(kind)
-  {}
-
-private:
-  const NdbDictionary::Column* m_column;  // Initial NULL, assigned w/ bindOperand()
-  /** This is used to tell the type of an NdbQueryOperand. This allow safe
-   * downcasting to a subclass.
-   */
-  const OperandKind m_kind;
-}; // class NdbQueryOperandImpl
-
-
-class NdbLinkedOperandImpl : public NdbQueryOperandImpl
-{
-  friend class NdbQueryBuilder;  // Allow privat access from builder interface
-
-public:
-  virtual int bindOperand(const NdbDictionary::Column& column,
-                          NdbQueryOperationDefImpl& operation);
-
-  const NdbQueryOperationDefImpl& getParentOperation() const
-  { return m_parentOperation;
-  }
-  // 'LinkedSrc' is index into parent op's spj-projection list where
-  // the refered column value is available
-  Uint32 getLinkedSrc() const
-  { return m_parentColumnIx;
-  }
-  const NdbDictionary::Column& getParentColumn() const
-  { return *m_parentOperation.getSPJProjection()[m_parentColumnIx];
-  }
-  virtual const NdbQueryOperand& getInterface() const
-  { return m_interface;
-  }
-
-private:
-  friend NdbQueryBuilderImpl::~NdbQueryBuilderImpl();
-  virtual ~NdbLinkedOperandImpl() {};
-
-  NdbLinkedOperandImpl (NdbQueryOperationDefImpl& parent, 
-                        Uint32 columnIx)
-   : NdbQueryOperandImpl(OperandKind_Linked),
-     m_interface(*this), 
-     m_parentOperation(parent),
-     m_parentColumnIx(columnIx)
-  {};
-
-  NdbLinkedOperand m_interface;
-  NdbQueryOperationDefImpl& m_parentOperation;
-  const Uint32 m_parentColumnIx;
-}; // class NdbLinkedOperandImpl
-
-
-class NdbParamOperandImpl : public NdbQueryOperandImpl
-{
-  friend class NdbQueryBuilder;  // Allow privat access from builder interface
-
-public:
-  const char* getName() const
-  { return m_name; };
-
-  Uint32 getEnum() const
-  { return 0; };  // FIXME
-
-  virtual const NdbQueryOperand& getInterface() const
-  { return m_interface;
-  }
-
-private:
-  friend NdbQueryBuilderImpl::~NdbQueryBuilderImpl();
-  virtual ~NdbParamOperandImpl() {};
-  NdbParamOperandImpl (const char* name)
-   : NdbQueryOperandImpl(OperandKind_Param),
-     m_interface(*this), 
-     m_name(name)
-  {};
-
-  NdbParamOperand m_interface;
-  const char* const m_name;     // Optional parameter name or NULL
-}; // class NdbParamOperandImpl
-
-
-/////////////////////////////////////////////////////
-// Pure virtual baseclass for ConstOperand.
-// Each specific const datatype has its own subclass.
-/////////////////////////////////////////////////////
-class NdbConstOperandImpl : public NdbQueryOperandImpl
-{
-  friend class NdbQueryBuilder;  // Allow privat access from builder interface
-public:
-  virtual size_t getLength() const = 0;
-  virtual const void* getAddr() const = 0;
-
-  virtual int bindOperand(const NdbDictionary::Column& column,
-                          NdbQueryOperationDefImpl& operation);
-
-  virtual NdbDictionary::Column::Type getType() const = 0;
-
-  virtual const NdbQueryOperand& getInterface() const
-  { return m_interface;
-  }
-
-protected:
-  friend NdbQueryBuilderImpl::~NdbQueryBuilderImpl();
-  virtual ~NdbConstOperandImpl() {};
-  NdbConstOperandImpl ()
-    : NdbQueryOperandImpl(OperandKind_Const),
-      m_interface(*this)
-  {};
-
-private:
-  NdbConstOperand m_interface;
-}; // class NdbConstOperandImpl
+//
+// The common baseclass 'class NdbQueryOperandImpl',
+// and its 'const', 'linked' and 'param' subclasses are
+// defined in "NdbQueryBuilderImpl.hpp"
+// The 'const' operand subclass is a pure virtual baseclass
+// which has different type specific subclasses defined below:
+//////////////////////////////////////////////////////////////
 
 //////////////////////////////////////////////////
 // Implements different const datatypes by further
-// subclassing of NdbConstOperand.
+// subclassing of the baseclass NdbConstOperand.
 //////////////////////////////////////////////////
 class NdbInt32ConstOperandImpl : public NdbConstOperandImpl
 {
@@ -313,7 +166,7 @@ private:
 // Implementation of NdbQueryOperation interface
 ////////////////////////////////////////////////
 
-// Common Baseclass 'class NdbQueryOperationDefImp' is 
+// Common Baseclass 'class NdbQueryOperationDefImpl' is 
 // defined in "NdbQueryBuilderImpl.hpp"
 
 
@@ -543,7 +396,7 @@ NdbParamOperand::getName() const
 Uint32
 NdbParamOperand::getEnum() const
 {
-  return ::getImpl(*this).getEnum();
+  return ::getImpl(*this).getParamIx();
 }
 
 /****************************************************************************
@@ -676,7 +529,7 @@ NdbQueryBuilder::constValue(const char* 
   NdbConstOperandImpl* constOp = new NdbCharConstOperandImpl(value);
   returnErrIf(constOp==0,4000);
 
-  m_pimpl->m_constOperands.push_back(constOp);
+  m_pimpl->m_operands.push_back(constOp);
   return &constOp->m_interface;
 }
 NdbConstOperand* 
@@ -686,7 +539,7 @@ NdbQueryBuilder::constValue(const void* 
   NdbConstOperandImpl* constOp = new NdbGenericConstOperandImpl(value,length);
   returnErrIf(constOp==0,4000);
 
-  m_pimpl->m_constOperands.push_back(constOp);
+  m_pimpl->m_operands.push_back(constOp);
   return &constOp->m_interface;
 }
 NdbConstOperand* 
@@ -695,7 +548,7 @@ NdbQueryBuilder::constValue(Int32 value)
   NdbConstOperandImpl* constOp = new NdbInt32ConstOperandImpl(value);
   returnErrIf(constOp==0,4000);
 
-  m_pimpl->m_constOperands.push_back(constOp);
+  m_pimpl->m_operands.push_back(constOp);
   return &constOp->m_interface;
 }
 NdbConstOperand* 
@@ -704,7 +557,7 @@ NdbQueryBuilder::constValue(Uint32 value
   NdbConstOperandImpl* constOp = new NdbUint32ConstOperandImpl(value);
   returnErrIf(constOp==0,4000);
 
-  m_pimpl->m_constOperands.push_back(constOp);
+  m_pimpl->m_operands.push_back(constOp);
   return &constOp->m_interface;
 }
 NdbConstOperand* 
@@ -713,7 +566,7 @@ NdbQueryBuilder::constValue(Int64 value)
   NdbConstOperandImpl* constOp = new NdbInt64ConstOperandImpl(value);
   returnErrIf(constOp==0,4000);
 
-  m_pimpl->m_constOperands.push_back(constOp);
+  m_pimpl->m_operands.push_back(constOp);
   return &constOp->m_interface;
 }
 NdbConstOperand* 
@@ -722,17 +575,17 @@ NdbQueryBuilder::constValue(Uint64 value
   NdbConstOperandImpl* constOp = new NdbUint64ConstOperandImpl(value);
   returnErrIf(constOp==0,4000);
 
-  m_pimpl->m_constOperands.push_back(constOp);
+  m_pimpl->m_operands.push_back(constOp);
   return &constOp->m_interface;
 }
 
 NdbParamOperand* 
 NdbQueryBuilder::paramValue(const char* name)
 {
-  NdbParamOperandImpl* paramOp = new NdbParamOperandImpl(name);
+  NdbParamOperandImpl* paramOp = new NdbParamOperandImpl(name,getImpl().m_paramCnt++);
   returnErrIf(paramOp==0,4000);
 
-  m_pimpl->m_paramOperands.push_back(paramOp);
+  m_pimpl->m_operands.push_back(paramOp);
   return &paramOp->m_interface;
 }
 
@@ -752,12 +605,12 @@ NdbQueryBuilder::linkedValue(const NdbQu
 
   // Locate refered parrent column in parent operations SPJ projection list;
   // Add if not already present
-  Uint32 spjRef = parentImpl.addColumnRef(column);
+  Uint32 colIx = parentImpl.addColumnRef(column);
 
-  NdbLinkedOperandImpl* linkedOp = new NdbLinkedOperandImpl(parentImpl,spjRef);
+  NdbLinkedOperandImpl* linkedOp = new NdbLinkedOperandImpl(parentImpl,colIx);
   returnErrIf(linkedOp==0, 4000);
 
-  m_pimpl->m_linkedOperands.push_back(linkedOp);
+  m_pimpl->m_operands.push_back(linkedOp);
   return &linkedOp->m_interface;
 }
 
@@ -953,8 +806,10 @@ NdbQueryBuilder::prepare()
 ////////////////////////////////////////
 
 NdbQueryBuilderImpl::NdbQueryBuilderImpl(Ndb& ndb)
-: m_ndb(ndb), m_error(), m_operations(),
-  m_paramOperands(), m_constOperands(), m_linkedOperands()
+: m_ndb(ndb), m_error(),
+  m_operations(),
+  m_operands(),
+  m_paramCnt(0)
 {}
 
 NdbQueryBuilderImpl::~NdbQueryBuilderImpl()
@@ -965,14 +820,8 @@ NdbQueryBuilderImpl::~NdbQueryBuilderImp
   for (i=0; i<m_operations.size(); ++i)
   { delete m_operations[i];
   }
-  for (i=0; i<m_paramOperands.size(); ++i)
-  { delete m_paramOperands[i];
-  }
-  for (i=0; i<m_constOperands.size(); ++i)
-  { delete m_constOperands[i];
-  }
-  for (i=0; i<m_linkedOperands.size(); ++i)
-  { delete m_linkedOperands[i];
+  for (i=0; i<m_operands.size(); ++i)
+  { delete m_operands[i];
   }
 }
 
@@ -1000,9 +849,7 @@ NdbQueryBuilderImpl::prepare()
     return NULL;
   }
   m_operations.clear();
-  m_paramOperands.clear();
-  m_constOperands.clear();
-  m_linkedOperands.clear();
+  m_operands.clear();
 
   return def;
 }
@@ -1013,9 +860,11 @@ NdbQueryBuilderImpl::prepare()
 NdbQueryDefImpl::
 NdbQueryDefImpl(const NdbQueryBuilderImpl& builder,
                 const Vector<NdbQueryOperationDefImpl*>& operations,
+                //const Vector<NdbQueryOperandImpl*> operands;  FIXME
                 int& error)
  : m_interface(*this), 
-   m_operations(operations)
+   m_operations(operations),
+   m_operands()
 {
   /* Sets size to 1, such that serialization of operation 0 will start from 
    * offset 1, leaving space for the length field.*/
@@ -1047,6 +896,9 @@ NdbQueryDefImpl::~NdbQueryDefImpl()
   for (Uint32 i=0; i<m_operations.size(); ++i)
   { delete m_operations[i];
   }
+  for (Uint32 i=0; i<m_operands.size(); ++i)
+  { delete m_operands[i];
+  }
 }
 
 const NdbQueryOperationDefImpl*
@@ -1106,43 +958,6 @@ NdbQueryLookupOperationDefImpl::NdbQuery
 }
 
 
-void 
-NdbQueryLookupOperationDefImpl
-::materializeRootOperands(NdbOperation& ndbOperation,
-                          const constVoidPtr actualParam[]) const
-{
-  assert(getQueryOperationIx()==0); // Should only be called for root operation.
-  const int keyCount = m_index==NULL ? 
-    getTable().getNoOfPrimaryKeys() :
-    static_cast<int>(getIndex()->getNoOfColumns());
-  int paramNo = 0;
-  int keyNo;
-  for(keyNo = 0; keyNo<keyCount; keyNo++){
-    switch(m_keys[keyNo]->getKind()){
-    case OperandKind_Const:
-      {
-        const NdbConstOperandImpl* const constOp 
-          = static_cast<const NdbConstOperandImpl*>(m_keys[keyNo]);
-        ndbOperation.equal(keyNo, 
-                           static_cast<const char*>(constOp->getAddr()));
-      }
-      break;
-    case OperandKind_Param:
-      assert(actualParam[paramNo] != NULL);
-      ndbOperation.equal(keyNo, 
-                         static_cast<const char*>(actualParam[paramNo++]));
-      break;
-    default:
-      // Root operation cannot have linked operands.
-      assert(false);
-    }
-  }
-  // All actual parameters should have been consumed.
-  assert(actualParam[paramNo] == NULL);
-  // All key fields should have been assigned a value. 
-  assert(m_keys[keyNo] == NULL);
-}
-
 NdbQueryIndexScanOperationDefImpl::NdbQueryIndexScanOperationDefImpl (
                            const NdbDictionary::Index& index,
                            const NdbDictionary::Table& table,
@@ -1190,6 +1005,44 @@ NdbQueryIndexScanOperationDefImpl::NdbQu
 
 
 void 
+NdbQueryLookupOperationDefImpl
+::materializeRootOperands(NdbOperation& ndbOperation,
+                          const constVoidPtr actualParam[]) const
+{
+  assert(getQueryOperationIx()==0); // Should only be called for root operation.
+  const int keyCount = m_index==NULL ? 
+    getTable().getNoOfPrimaryKeys() :
+    static_cast<int>(getIndex()->getNoOfColumns());
+  int paramNo = 0;
+  int keyNo;
+  for(keyNo = 0; keyNo<keyCount; keyNo++){
+    switch(m_keys[keyNo]->getKind()){
+    case NdbQueryOperandImpl::Const:
+      {
+        const NdbConstOperandImpl* const constOp 
+          = static_cast<const NdbConstOperandImpl*>(m_keys[keyNo]);
+        ndbOperation.equal(keyNo, 
+                           static_cast<const char*>(constOp->getAddr()));
+      }
+      break;
+    case NdbQueryOperandImpl::Param:
+      assert(actualParam[paramNo] != NULL);
+      ndbOperation.equal(keyNo, 
+                         static_cast<const char*>(actualParam[paramNo++]));
+      break;
+    default:
+      // Root operation cannot have linked operands.
+      assert(false);
+    }
+  }
+  // All actual parameters should have been consumed.
+  // assert(actualParam[paramNo] == NULL); // FIXME: param[] might be NULL
+  // All key fields should have been assigned a value. 
+  assert(m_keys[keyNo] == NULL);
+}
+
+
+void 
 NdbQueryIndexScanOperationDefImpl
 ::materializeRootOperands(NdbOperation& ndbOperation,
                           const constVoidPtr actualParam[]) const
@@ -1205,6 +1058,7 @@ NdbQueryTableScanOperationDefImpl
   assert(false); // TODO: Implement this.
 }
 
+
 void
 NdbQueryOperationDefImpl::addParent(NdbQueryOperationDefImpl* parentOp)
 {
@@ -1263,6 +1117,16 @@ NdbLinkedOperandImpl::bindOperand(
 
 
 int
+NdbParamOperandImpl::bindOperand(
+                           const NdbDictionary::Column& column,
+                           NdbQueryOperationDefImpl& operation)
+{
+  operation.addParamRef(this);
+  return NdbQueryOperandImpl::bindOperand(column,operation);
+}
+
+
+int
 NdbConstOperandImpl::bindOperand(
                            const NdbDictionary::Column& column,
                            NdbQueryOperationDefImpl& operation)
@@ -1327,11 +1191,14 @@ private:
 
 // Find offset (in 32-bit words) of field within struct QN_ScanFragNode.
 #define POS_IN_SCAN(field) (offsetof(QN_ScanFragNode, field)/sizeof(Uint32)) 
+
 //#define POS_IN_QUERY(field) (offsetof(QueryNode, field)/sizeof(Uint32)) 
 
+
 int
 NdbQueryLookupOperationDefImpl
-::serializeOperation(Uint32Buffer& serializedDef) const{
+::serializeOperation(Uint32Buffer& serializedDef) const
+{
   Uint32Slice nodeBuffer(serializedDef, serializedDef.getSize());
   QN_LookupNode& node = reinterpret_cast<QN_LookupNode&>
     (nodeBuffer.get(0, SIZE_IN_WORDS(QN_LookupNode)));
@@ -1368,14 +1235,14 @@ NdbQueryLookupOperationDefImpl
   const NdbQueryOperandImpl* op = m_keys[0];
   while(op!=NULL){
     switch(op->getKind()){
-    case OperandKind_Linked:
+    case NdbQueryOperandImpl::Linked:
     {
       node.requestInfo |= DABits::NI_KEY_LINKED;
       const NdbLinkedOperandImpl& linkedOp = *static_cast<const NdbLinkedOperandImpl*>(op);
-      keyPattern.get(keyPatternPos++) = QueryPattern::col(linkedOp.getLinkedSrc());
+      keyPattern.get(keyPatternPos++) = QueryPattern::col(linkedOp.getLinkedColumnIx());
       break;
     }
-    case OperandKind_Const:
+    case NdbQueryOperandImpl::Const:
     {
       node.requestInfo |= DABits::NI_KEY_CONSTS;
       const NdbConstOperandImpl& constOp 
@@ -1395,11 +1262,10 @@ NdbQueryLookupOperationDefImpl
       keyPatternPos += wordCount;
       break;
     }
-    case OperandKind_Param:  // TODO: Implement this
-/**** FIXME: can't set NI_KEY_PARAMS yet as this also require PI_KEY_PARAMS in parameter part
+    case NdbQueryOperandImpl::Param:  // TODO: Implement this
+      /**** FIXME: can't set NI_KEY_PARAMS yet as this also require PI_KEY_PARAMS in parameter part *****/
       node.requestInfo |= DABits::NI_KEY_PARAMS;
       paramCnt++;
-*****/
       keyPattern.get(keyPatternPos++) = QueryPattern::data(0);  // Simple hack to avoid 'assert(keyPatternPos>0)' below
       break;
     default:
@@ -1444,6 +1310,8 @@ NdbQueryLookupOperationDefImpl
   return 0;
 }
 
+
+
 int
 NdbQueryTableScanOperationDefImpl
 ::serializeOperation(Uint32Buffer& serializedDef) const
@@ -1513,9 +1381,9 @@ NdbQueryIndexScanOperationDefImpl
 
 // Instantiate Vector templates
 template class Vector<NdbQueryOperationDefImpl*>;
-template class Vector<NdbParamOperandImpl*>;
-template class Vector<NdbConstOperandImpl*>;
-template class Vector<NdbLinkedOperandImpl*>;
+template class Vector<NdbQueryOperandImpl*>;
+
+template class Vector<const NdbParamOperandImpl*>;
 template class Vector<const NdbDictionary::Column*>;
 
 #if 0

=== modified file 'storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp	2009-07-16 12:11:21 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp	2009-07-24 08:55:33 +0000
@@ -168,9 +168,7 @@ private:
   NdbQueryDef m_interface;
 
   Vector<NdbQueryOperationDefImpl*> m_operations;
-//Vector<NdbParamOperand*> m_paramOperand;
-//Vector<NdbConstOperand*> m_constOperand;
-//Vector<NdbLinkedOperand*> m_linkedOperand;
+  Vector<NdbQueryOperandImpl*> m_operands;
   Uint32Buffer m_serializedDef; 
 }; // class NdbQueryDefImpl
 
@@ -204,17 +202,18 @@ private:
   NdbError m_error;
 
   Vector<NdbQueryOperationDefImpl*> m_operations;
-  Vector<NdbParamOperandImpl*> m_paramOperands;
-  Vector<NdbConstOperandImpl*> m_constOperands;
-  Vector<NdbLinkedOperandImpl*> m_linkedOperands;
-
+  Vector<NdbQueryOperandImpl*> m_operands;
+  Uint32 m_paramCnt;
 }; // class NdbQueryBuilderImpl
 
 
+////////////////////////////////////////////////
+// Implementation of NdbQueryOperation interface
+////////////////////////////////////////////////
+
 /** For making complex declarations more readable.*/
 typedef const void* constVoidPtr;
 
-
 class NdbQueryOperationDefImpl
 {
 public:
@@ -230,25 +229,25 @@ public:
 
   // Get the ordinal position of this operation within the query
   Uint32 getQueryOperationIx() const
-  { return m_ix; };
+  { return m_ix; }
 
   Uint32 getNoOfParentOperations() const
-  { return m_parents.size(); };
+  { return m_parents.size(); }
 
   const NdbQueryOperationDefImpl& getParentOperation(Uint32 i) const
-  { return *m_parents[i]; };
+  { return *m_parents[i]; }
 
   Uint32 getNoOfChildOperations() const
-  { return m_children.size(); };
+  { return m_children.size(); }
 
   const NdbQueryOperationDefImpl& getChildOperation(Uint32 i) const
-  { return *m_children[i]; };
+  { return *m_children[i]; }
 
   const NdbDictionary::Table& getTable() const
-  { return m_table; };
+  { return m_table; }
 
   const char* getName() const
-  { return m_ident; };
+  { return m_ident; }
 
   // Register a operation as parent of this operation
   void addParent(NdbQueryOperationDefImpl*);
@@ -257,8 +256,22 @@ public:
   void addChild(NdbQueryOperationDefImpl*);
 
   // Register a linked reference to a column from operation
+  // Return position in list of refered columns available from
+  // this (parent) operation. Child ops later refer linked 
+  // columns by its position in this list
   Uint32 addColumnRef(const NdbDictionary::Column*);
 
+  // Register a param operand which is refered by this operation.
+  // Param values are supplied pr. operation when code is serialized.
+  void addParamRef(const NdbParamOperandImpl* param)
+  { m_params.push_back(param); }
+
+  Uint32 getNoOfParameters() const
+  { return m_params.size(); }
+
+  const NdbParamOperandImpl& getParameter(Uint32 ix) const
+  { return *m_params[ix]; }
+
   // Get type of query operation
   virtual Type getType() const = 0;
 
@@ -295,21 +308,180 @@ protected:
                                      const char* ident,
                                      Uint32      ix)
    : m_table(table), m_ident(ident), m_ix(ix),
-     m_parents(), m_children(),
+     m_parents(), m_children(), m_params(),
      m_spjProjection()
- {};
+  {}
 
 private:
   const NdbDictionary::Table& m_table;
   const char* const m_ident; // Optional name specified by aplication
-  const Uint32 m_ix;         // Index if this operation within operation array
+  const Uint32 m_ix;         // Index of this operation within operation array
 
   // parent / child vectors contains dependencies as defined
   // with linkedValues
   Vector<NdbQueryOperationDefImpl*> m_parents;
   Vector<NdbQueryOperationDefImpl*> m_children;
+
+  // Params required by this operation
+  Vector<const NdbParamOperandImpl*> m_params;
+
+  // Column from this operation required by its child operations
   Vector<const NdbDictionary::Column*> m_spjProjection;
 }; // class NdbQueryOperationDefImpl
 
+
+//////////////////////////////////////////////
+// Implementation of NdbQueryOperand interface
+//////////////////////////////////////////////
+
+// Baseclass for the QueryOperand implementation
+class NdbQueryOperandImpl
+{
+public:
+
+  /** The type of an operand. This corresponds to the set of subclasses
+   * of NdbQueryOperandImpl.
+   */
+  enum Kind {
+    Linked,
+    Param,
+    Const
+  };
+
+  const NdbDictionary::Column* getColumn() const
+  { return m_column; }
+
+  virtual int bindOperand(const NdbDictionary::Column& column,
+                          NdbQueryOperationDefImpl& operation)
+  { if (m_column  && m_column != &column)
+      // Already bounded to a different column
+      return QRY_OPERAND_ALREADY_BOUND;
+    m_column = &column;
+    return 0;
+  }
+  
+  virtual const NdbQueryOperand& getInterface() const = 0; 
+
+  Kind getKind() const
+  { return m_kind; }
+
+protected:
+  friend NdbQueryBuilderImpl::~NdbQueryBuilderImpl();
+  friend NdbQueryDefImpl::~NdbQueryDefImpl();
+
+  virtual ~NdbQueryOperandImpl()=0;
+
+  NdbQueryOperandImpl(Kind kind)
+    : m_column(0),
+      m_kind(kind)
+  {}
+
+private:
+  const NdbDictionary::Column* m_column;  // Initial NULL, assigned w/ bindOperand()
+  /** This is used to tell the type of an NdbQueryOperand. This allow safe
+   * downcasting to a subclass.
+   */
+  const Kind m_kind;
+}; // class NdbQueryOperandImpl
+
+
+class NdbLinkedOperandImpl : public NdbQueryOperandImpl
+{
+  friend class NdbQueryBuilder;  // Allow privat access from builder interface
+
+public:
+  virtual int bindOperand(const NdbDictionary::Column& column,
+                          NdbQueryOperationDefImpl& operation);
+
+  const NdbQueryOperationDefImpl& getParentOperation() const
+  { return m_parentOperation; }
+
+  // 'LinkedSrc' is index into parent op's spj-projection list where
+  // the refered column value is available
+  Uint32 getLinkedColumnIx() const
+  { return m_parentColumnIx; }
+
+  const NdbDictionary::Column& getParentColumn() const
+  { return *m_parentOperation.getSPJProjection()[m_parentColumnIx]; }
+
+  virtual const NdbQueryOperand& getInterface() const
+  { return m_interface; }
+
+private:
+  virtual ~NdbLinkedOperandImpl() {};
+
+  NdbLinkedOperandImpl (NdbQueryOperationDefImpl& parent, 
+                        Uint32 columnIx)
+   : NdbQueryOperandImpl(Linked),
+     m_interface(*this), 
+     m_parentOperation(parent),
+     m_parentColumnIx(columnIx)
+  {}
+
+  NdbLinkedOperand m_interface;
+  NdbQueryOperationDefImpl& m_parentOperation;
+  const Uint32 m_parentColumnIx;
+}; // class NdbLinkedOperandImpl
+
+
+class NdbParamOperandImpl : public NdbQueryOperandImpl
+{
+  friend class NdbQueryBuilder;  // Allow privat access from builder interface
+
+public:
+  virtual int bindOperand(const NdbDictionary::Column& column,
+                          NdbQueryOperationDefImpl& operation);
+
+  const char* getName() const
+  { return m_name; }
+
+  Uint32 getParamIx() const
+  { return m_paramIx; }
+
+  virtual const NdbQueryOperand& getInterface() const
+  { return m_interface; }
+
+private:
+  virtual ~NdbParamOperandImpl() {};
+  NdbParamOperandImpl (const char* name, Uint32 paramIx)
+   : NdbQueryOperandImpl(Param),
+     m_interface(*this), 
+     m_name(name),
+     m_paramIx(paramIx)
+  {}
+
+  NdbParamOperand m_interface;
+  const char* const m_name;     // Optional parameter name or NULL
+  const Uint32 m_paramIx;
+}; // class NdbParamOperandImpl
+
+
+class NdbConstOperandImpl : public NdbQueryOperandImpl
+{
+  friend class NdbQueryBuilder;  // Allow privat access from builder interface
+public:
+  virtual size_t getLength() const = 0;
+  virtual const void* getAddr() const = 0;
+
+  virtual int bindOperand(const NdbDictionary::Column& column,
+                          NdbQueryOperationDefImpl& operation);
+
+  virtual NdbDictionary::Column::Type getType() const = 0;
+
+  virtual const NdbQueryOperand& getInterface() const
+  { return m_interface; }
+
+protected:
+  virtual ~NdbConstOperandImpl() {};
+  NdbConstOperandImpl ()
+    : NdbQueryOperandImpl(Const),
+      m_interface(*this)
+  {}
+
+private:
+  NdbConstOperand m_interface;
+}; // class NdbConstOperandImpl
+
+
 #endif // __cplusplus
 #endif

=== modified file 'storage/ndb/src/ndbapi/NdbQueryOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbQueryOperation.cpp	2009-07-16 12:11:21 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryOperation.cpp	2009-07-24 08:55:33 +0000
@@ -22,6 +22,7 @@
 #include "NdbQueryBuilder.hpp"
 #include "NdbQueryBuilderImpl.hpp"
 #include "signaldata/QueryTree.hpp"
+
 #include "AttributeHeader.hpp"
 #include "NdbRecord.hpp"
 
@@ -225,15 +226,14 @@ NdbQueryImpl::NdbQueryImpl(NdbTransactio
       {
         NdbOperation* lookupOp = m_transaction.getNdbOperation(&def.getTable());
         lookupOp->readTuple(NdbOperation::LM_Dirty);
-        lookupOp->m_isLinked = true;
+        lookupOp->m_isLinked = true; //(queryDef.getNoOfOperations()>1);
         lookupOp->setQueryImpl(this);
         m_ndbOperation = lookupOp;
       }
       else if (def.getType() == NdbQueryOperationDefImpl::TableScan)
       {
         NdbScanOperation* scanOp = m_transaction.scanTable(def.getTable().getDefaultRecord(), NdbOperation::LM_Dirty);
-//      scanOp->readTuples(NdbOperation::LM_Dirty);
-        scanOp->m_isLinked = true;
+        scanOp->m_isLinked = true; // if (queryDef.getNoOfOperations()> 1);
         scanOp->setQueryImpl(this);
         m_ndbOperation = scanOp;
       } else {
@@ -351,19 +351,15 @@ NdbQueryImpl::prepareSend(){
   // Serialize parameters.
   for(Uint32 i = 0; i < m_operations.size(); i++){
     const int error = m_operations[i]->prepareSend(m_serializedParams);
-    if(error != 0){
+    if(unlikely(error != 0)){
       return error;
     }
   }
-  // Append serialized query tree and params to ATTRINFO of the NdnOperation.
-  m_ndbOperation->insertATTRINFOloop(&m_queryDef.getSerialized().get(0),
-                                     m_queryDef.getSerialized().getSize());
-  m_ndbOperation->insertATTRINFOloop(&m_serializedParams.get(0), 
-                                     m_serializedParams.getSize());
 
   // Build explicit key/filter/bounds for root operation.
   m_operations[0]->getQueryOperationDef()
     .materializeRootOperands(*getNdbOperation(), m_param);
+
 #ifdef TRACE_SERIALIZATION
   ndbout << "Serialized params for all : ";
   for(Uint32 i = 0; i < m_serializedParams.getSize(); i++){
@@ -373,6 +369,29 @@ NdbQueryImpl::prepareSend(){
   }
   ndbout << endl;
 #endif
+
+  // Append serialized query tree and params to ATTRINFO of the NdnOperation.
+  //
+  // Handled differently depending on if the operation is a NdbRecord type operation
+  // (Long signals) or a old type NdbApi operation.(Short signals)
+  // NOTE1: All scans are 'NdbRecord'
+  // NOTE2: It should be our goal to remove the dependency of the existing 
+  //        NdbOperations for building signals for NdbQueryOperations
+  if (m_ndbOperation->isNdbRecordOperation())
+  {
+    m_ndbOperation->insertATTRINFOData_NdbRecord((char*)&m_queryDef.getSerialized().get(0),
+                                       m_queryDef.getSerialized().getSize()*4);
+    m_ndbOperation->insertATTRINFOData_NdbRecord((char*)&m_serializedParams.get(0), 
+                                       m_serializedParams.getSize()*4);
+  }
+  else
+  {
+    m_ndbOperation->insertATTRINFOloop(&m_queryDef.getSerialized().get(0),
+                                       m_queryDef.getSerialized().getSize());
+    m_ndbOperation->insertATTRINFOloop(&m_serializedParams.get(0), 
+                                       m_serializedParams.getSize());
+  }
+
   return 0;
 }
 
@@ -461,7 +480,7 @@ NdbQueryOperationImpl::getValue(
   const NdbDictionary::Column* const column 
     = m_operationDef.getTable().getColumn(anAttrName);
   if(unlikely(column==NULL)){
-    return NULL;
+    return NULL;  // FIXME: Don't return NULL wo/ setting errorcode
   } else {
     return getValue(column, resultBuffer);
   }
@@ -563,6 +582,7 @@ NdbQueryOperationImpl::UserProjection
 ::UserProjection(const NdbDictionary::Table& tab):
   m_columnCount(0),
   m_noOfColsInTable(tab.getNoOfColumns()),
+  m_mask(),
   m_isOrdered(true),
   m_maxColNo(-1){
   assert(m_noOfColsInTable<=MAX_ATTRIBUTES_IN_TABLE);
@@ -645,16 +665,22 @@ int NdbQueryOperationImpl::prepareSend(U
 
   int optPos = 0;
 
+  //printf("operation has %d params\n", getQueryOperationDef().getNoOfParameters());
+
   // SPJ block assume PARAMS to be supplied before ATTR_LIST
-  if (false)  // TODO: Check if serialized tree code has 'NI_KEY_PARAMS'
+  if (getQueryOperationDef().getNoOfParameters() > 0)
   {
     int size = 0;
     requestInfo |= DABits::PI_KEY_PARAMS;
     Uint32Slice keyParam(optional, optPos);
 
-    assert (getQuery().getParam(0) != NULL);
     // FIXME: Add parameters here, unsure about the serialized format yet
-
+    for (Uint32 i=0; i<getQueryOperationDef().getNoOfParameters(); i++)
+    {
+      const NdbParamOperandImpl& param = getQueryOperationDef().getParameter(i);
+      const void* paramValue = getQuery().getParamValue(param.getParamIx());
+      assert (paramValue != NULL);
+    }
     optPos += size;
   }
 
@@ -698,7 +724,6 @@ void NdbQueryOperationImpl::release(){
 }
 
 
-
 bool 
 NdbQueryOperationImpl::execTRANSID_AI(const Uint32* ptr, Uint32 len){
   ndbout << "NdbQueryOperationImpl::execTRANSID_AI(): *this="
@@ -736,8 +761,9 @@ NdbQueryOperationImpl::execTRANSID_AI(co
   return false;
 }
 
+
 bool 
-NdbQueryOperationImpl::execTCKEYREF(){
+NdbQueryOperationImpl::execTCKEYREF(NdbApiSignal* aSignal){
   ndbout << "NdbQueryOperationImpl::execTCKEYREF(): *this="
 	 << *this << endl;
   m_pendingResults--;
@@ -754,7 +780,6 @@ NdbQueryOperationImpl::execTCKEYREF(){
 }
 
 
-
 /** For debugging.*/
 NdbOut& operator<<(NdbOut& out, const NdbQueryOperationImpl& op){
   out << "[ this: " << &op

=== modified file 'storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp	2009-07-16 12:11:21 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp	2009-07-24 08:55:33 +0000
@@ -82,8 +82,11 @@ public:
   /** Release all NdbReceiver instances.*/
   void release();
 
-  bool checkMagicNumber() const { return m_magic == MAGIC;}
-  Uint32 ptr2int() const {return m_id;}
+  bool checkMagicNumber() const
+  { return m_magic == MAGIC; }
+
+  Uint32 ptr2int() const
+  { return m_id; }
   
   const NdbQuery& getInterface() const
   { return m_interface; }
@@ -91,14 +94,17 @@ public:
   NdbQuery& getInterface()
   { return m_interface; }
   
-  const void* getParam(Uint32 i) const
-  { return m_param[i]; }
+  const void* getParamValue(Uint32 ix) const
+  { return m_param[ix]; }
 
   /** Get next query in same transaction.*/
-  NdbQueryImpl* getNext() const {return m_next;}
+  NdbQueryImpl* getNext() const
+  { return m_next; }
 
   /** TODO: Remove. Temporary hack for prototype.*/
-  NdbOperation* getNdbOperation() const {return m_ndbOperation;}
+  NdbOperation* getNdbOperation() const
+  { return m_ndbOperation; }
+
 private:
   NdbQuery m_interface;
 
@@ -191,7 +197,7 @@ public:
   
   /** Process absence of result data for this operation. 
    * Return true if query complete.*/
-  bool execTCKEYREF();
+  bool execTCKEYREF(NdbApiSignal* aSignal);
 
   /** Prepare for execution. 
    *  @return possible error code.*/
@@ -246,7 +252,7 @@ private:
     int m_columnCount;
     /** The number of columns in the table that the operation refers to.*/
     const int m_noOfColsInTable;
-    /** User Projection, represented as a bitmap (indexd with column numbers).*/
+    /** User Projection, represented as a bitmap (indexed with column numbers).*/
     Bitmask<MAXNROFATTRIBUTESINWORDS> m_mask;
     /** True if columns were added in ascending order (ordered according to 
      * column number).*/

=== modified file 'storage/ndb/src/ndbapi/Ndbif.cpp'
--- a/storage/ndb/src/ndbapi/Ndbif.cpp	2009-07-10 07:41:22 +0000
+++ b/storage/ndb/src/ndbapi/Ndbif.cpp	2009-07-24 08:55:33 +0000
@@ -549,7 +549,7 @@ Ndb::handleReceivedSignal(NdbApiSignal* 
               return;
             }//if
           } else {
-            if(queryOpImpl->execTCKEYREF() &&
+            if(queryOpImpl->execTCKEYREF(aSignal) &&
                tCon->OpCompleteFailure(queryOpImpl->getQuery()
                                        .getNdbOperation()) != -1){
               completedTransaction(tCon);


Attachment: [text/bzr-bundle] bzr/jan.wedvik@sun.com-20090724085533-nsgl1kjp6apk7lv1.bundle
Thread
bzr commit into mysql-5.1-telco-7.0-spj branch (jan.wedvik:2936) Jan Wedvik24 Jul