#At file:///export/home2/tmp/jw1159207/mysql/mysql-5.1-telco-7.0-spj/ based on revid:jan.wedvik@stripped4008-5ley5iqnyhiads6i
2940 Jan Wedvik 2009-08-07
Before changing NdbQueryOperationImpl *not* to count TCKEYREF
messages when root operation is a scan.
modified:
storage/ndb/include/ndbapi/Ndb.hpp
storage/ndb/include/ndbapi/NdbQueryOperation.hpp
storage/ndb/include/ndbapi/NdbReceiver.hpp
storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp
storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp
storage/ndb/src/kernel/blocks/dbtc/DbtcMain.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/NdbReceiver.cpp
storage/ndb/src/ndbapi/NdbTransactionScan.cpp
storage/ndb/src/ndbapi/Ndbif.cpp
storage/ndb/src/ndbapi/TransporterFacade.cpp
storage/ndb/src/ndbapi/ndberror.c
storage/ndb/test/tools/test_spj.cpp
=== modified file 'storage/ndb/include/ndbapi/Ndb.hpp'
--- a/storage/ndb/include/ndbapi/Ndb.hpp 2009-08-04 07:40:08 +0000
+++ b/storage/ndb/include/ndbapi/Ndb.hpp 2009-08-07 09:33:27 +0000
@@ -1073,8 +1073,6 @@ class Ndb
friend class NdbScanFilterImpl;
friend class NdbQueryImpl;
friend class NdbQueryOperationImpl;
- friend class NdbQueryReceiver;
- friend class NdbMappable;
#endif
public:
=== modified file 'storage/ndb/include/ndbapi/NdbQueryOperation.hpp'
--- a/storage/ndb/include/ndbapi/NdbQueryOperation.hpp 2009-07-24 08:55:33 +0000
+++ b/storage/ndb/include/ndbapi/NdbQueryOperation.hpp 2009-08-07 09:33:27 +0000
@@ -221,7 +221,7 @@ public:
const unsigned char* result_mask = 0);
int setResultRowRef (const NdbRecord* rec,
- char* & bufRef,
+ const char* & bufRef,
const unsigned char* result_mask = 0);
// TODO: define how BLOB/CLOB should be retrieved.
=== modified file 'storage/ndb/include/ndbapi/NdbReceiver.hpp'
--- a/storage/ndb/include/ndbapi/NdbReceiver.hpp 2009-08-04 07:40:08 +0000
+++ b/storage/ndb/include/ndbapi/NdbReceiver.hpp 2009-08-07 09:33:27 +0000
@@ -33,14 +33,13 @@ class NdbReceiver
friend class Ndb;
friend class NdbOperation;
friend class NdbQueryImpl;
- // friend class NdbQueryOperation;
- friend class NdbQueryLookupOperationImpl;
- friend class NdbQueryScanOperationImpl;
- friend class NdbQueryReceiver;
+ friend class NdbQueryOperation;
+ friend class NdbQueryOperationImpl;
friend class NdbScanOperation;
friend class NdbIndexOperation;
friend class NdbIndexScanOperation;
friend class NdbTransaction;
+ friend int spjTest(int argc, char** argv);
public:
enum ReceiverType { NDB_UNINITIALIZED,
@@ -90,7 +89,7 @@ private:
void getValues(const NdbRecord*, char*);
void prepareSend();
void calculate_batch_size(Uint32, Uint32, Uint32&, Uint32&, Uint32&,
- const NdbRecord *);
+ const NdbRecord *) const;
/*
Set up buffers for receiving TRANSID_AI and KEYINFO20 signals
during a scan using NdbRecord.
=== modified file 'storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp 2009-07-17 21:57:40 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/Dbspj.hpp 2009-08-07 09:33:27 +0000
@@ -210,6 +210,15 @@ public:
* should only do local cleanup(s)
*/
void (Dbspj::*m_cleanup)(Ptr<Request>, Ptr<TreeNode>);
+
+ /**
+ * This function is called on the root operation when a LQHKEYCONF,
+ * LQKEYREF or LQHKEYREQ signal is sent or received on behalf of a
+ * descendant operation*/
+ void (Dbspj::*m_count_descendant_signal)(Signal* signal,
+ Ptr<Request> requestPtr,
+ Ptr<TreeNode> rootPtr,
+ Uint32 globalSignalNo);
};
struct LookupData
@@ -242,8 +251,19 @@ public:
Uint32 m_scan_state; // Only valid is TreeNodeState >= TN_ACTIVE
Uint32 m_scan_status; // fragmentCompleted
+ /** True if signal has been received since sending
+ * last SCAN_FRAGREQ/SCAN_NEXTREQ*/
+ bool m_scan_fragconf_received;
Uint32 m_rows_received; // #execTRANSID_AI
Uint32 m_rows_expecting; // ScanFragConf
+ /** Number of receiced LQHKEYCONF messages from descendant lookup
+ * operations.*/
+ Uint32 m_descendant_keyconfs_received;
+ /** Number of received LQHKEYREF messages from descendant lookup
+ * operations.*/
+ Uint32 m_descendant_keyrefs_received;
+ /** Number of LQHKEYREQ messages sent for descendant lookup operations.*/
+ Uint32 m_descendant_keyreqs_sent;
Uint32 m_scanFragReq[ScanFragReq::SignalLength + 1];
};
@@ -485,7 +505,9 @@ private:
DABuffer param, Uint32 paramBits);
Uint32 zeroFill(Uint32 & ptrI, Uint32 cnt);
-
+ /** Find root operation.*/
+ const Ptr<TreeNode> getRoot(TreeNode_list::Head& head);
+
/**
* Lookup
*/
@@ -500,6 +522,10 @@ private:
void lookup_execLQHKEYCONF(Signal*, Ptr<Request>, Ptr<TreeNode>);
void lookup_start_child(Signal*, Ptr<Request>, Ptr<TreeNode>, const RowRef &);
void lookup_cleanup(Ptr<Request>, Ptr<TreeNode>);
+ void lookup_count_descendant_signal(Signal* signal,
+ Ptr<Request> requestPtr,
+ Ptr<TreeNode> rootPtr,
+ Uint32 globalSignalNo){};
Uint32 computeHash(Signal*, BuildKeyReq&, Uint32 table, Uint32 keyInfoPtrI);
Uint32 getNodes(Signal*, BuildKeyReq&, Uint32 tableId);
@@ -519,6 +545,10 @@ private:
void scanFrag_batch_complete(Signal*, Ptr<Request>, Ptr<TreeNode>);
void scanFrag_start_child(Signal*,Ptr<Request>,Ptr<TreeNode>, const RowRef &);
void scanFrag_cleanup(Ptr<Request>, Ptr<TreeNode>);
+ void scanFrag_count_descendant_signal(Signal* signal,
+ Ptr<Request> requestPtr,
+ Ptr<TreeNode> rootPtr,
+ Uint32 globalSignalNo);
/**
* Scratch buffers...
=== modified file 'storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp 2009-07-24 08:55:33 +0000
+++ b/storage/ndb/src/kernel/blocks/dbspj/DbspjMain.cpp 2009-08-07 09:33:27 +0000
@@ -1020,7 +1020,8 @@ Dbspj::g_LookupOpInfo =
0, // Dbspj::lookup_execSCAN_NEXTREQ
0, // Dbspj::lookup_complete
0, // Dbspj::lookup_abort
- &Dbspj::lookup_cleanup
+ &Dbspj::lookup_cleanup,
+ &Dbspj::lookup_count_descendant_signal
};
Uint32
@@ -1283,6 +1284,12 @@ Dbspj::lookup_send(Signal* signal,
add = 1;
}
treeNodePtr.p->m_lookup_data.m_outstanding += add;
+
+ Ptr<TreeNode> root = getRoot(requestPtr.p->m_nodes);
+ (this->*(root.p->m_info->m_count_descendant_signal))(NULL,
+ requestPtr,
+ root,
+ GSN_LQHKEYREQ);
}
void
@@ -1365,6 +1372,12 @@ Dbspj::lookup_execLQHKEYREF(Signal* sign
jam();
nodeFinished(signal, requestPtr, treeNodePtr);
}
+
+ Ptr<TreeNode> root = getRoot(requestPtr.p->m_nodes);
+ (this->*(root.p->m_info->m_count_descendant_signal))(signal,
+ requestPtr,
+ root,
+ GSN_LQHKEYREF);
}
void
@@ -1380,6 +1393,12 @@ Dbspj::lookup_execLQHKEYCONF(Signal* sig
jam();
nodeFinished(signal, requestPtr, treeNodePtr);
}
+
+ Ptr<TreeNode> root = getRoot(requestPtr.p->m_nodes);
+ (this->*(root.p->m_info->m_count_descendant_signal))(signal,
+ requestPtr,
+ root,
+ GSN_LQHKEYCONF);
}
void
@@ -1552,7 +1571,8 @@ Dbspj::g_ScanFragOpInfo =
0, // Dbspj::scanFrag_execSCAN_NEXTREQ
0, // Dbspj::scanFrag_complete
0, // Dbspj::scanFrag_abort
- &Dbspj::scanFrag_cleanup
+ &Dbspj::scanFrag_cleanup,
+ &Dbspj::scanFrag_count_descendant_signal
};
Uint32
@@ -1805,8 +1825,24 @@ Dbspj::scanFrag_send(Signal* signal,
treeNodePtr.p->m_scanfrag_data.m_scan_state = ScanFragData::SF_RUNNING;
treeNodePtr.p->m_scanfrag_data.m_scan_status = 0;
+ treeNodePtr.p->m_scanfrag_data.m_scan_fragconf_received = false;
treeNodePtr.p->m_scanfrag_data.m_rows_received = 0;
treeNodePtr.p->m_scanfrag_data.m_rows_expecting = 0;
+ treeNodePtr.p->m_scanfrag_data.m_descendant_keyconfs_received = 0;
+ treeNodePtr.p->m_scanfrag_data.m_descendant_keyrefs_received = 0;
+ treeNodePtr.p->m_scanfrag_data.m_descendant_keyreqs_sent = 0;
+}
+
+/** Return true if scan is complete. This happens when all scan rows have */
+static bool isScanComplete(const Dbspj::ScanFragData& scanFragData)
+{
+ return scanFragData.m_scan_fragconf_received &&
+ // All rows for root scan received.
+ scanFragData.m_rows_received == scanFragData.m_rows_expecting &&
+ // All rows for descendant lookups received.
+ scanFragData.m_descendant_keyreqs_sent ==
+ scanFragData.m_descendant_keyconfs_received +
+ scanFragData.m_descendant_keyrefs_received;
}
void
@@ -1818,10 +1854,6 @@ Dbspj::scanFrag_execTRANSID_AI(Signal* s
jam();
treeNodePtr.p->m_scanfrag_data.m_rows_received++;
- const bool done =
- treeNodePtr.p->m_scanfrag_data.m_rows_expecting ==
- treeNodePtr.p->m_scanfrag_data.m_rows_received;
-
{
LocalArenaPoolImpl pool(requestPtr.p->m_arena, m_dependency_map_pool);
Local_dependency_map list(pool, treeNodePtr.p->m_dependent_nodes);
@@ -1837,8 +1869,7 @@ Dbspj::scanFrag_execTRANSID_AI(Signal* s
}
}
- if (done)
- {
+ if(isScanComplete(treeNodePtr.p->m_scanfrag_data)){
jam();
scanFrag_batch_complete(signal, requestPtr, treeNodePtr);
}
@@ -1869,9 +1900,8 @@ Dbspj::scanFrag_execSCAN_FRAGCONF(Signal
treeNodePtr.p->m_scanfrag_data.m_scan_status = done;
treeNodePtr.p->m_scanfrag_data.m_rows_expecting = rows;
-
- if (rows == treeNodePtr.p->m_scanfrag_data.m_rows_received)
- {
+ treeNodePtr.p->m_scanfrag_data.m_scan_fragconf_received = true;
+ if(isScanComplete(treeNodePtr.p->m_scanfrag_data)){
jam();
scanFrag_batch_complete(signal, requestPtr, treeNodePtr);
}
@@ -1894,13 +1924,13 @@ Dbspj::scanFrag_batch_complete(Signal* s
conf->senderData = requestPtr.p->m_senderData;
conf->transId1 = requestPtr.p->m_transId[0];
conf->transId2 = requestPtr.p->m_transId[1];
- conf->completedOps = treeNodePtr.p->m_scanfrag_data.m_rows_expecting;
+ conf->completedOps = treeNodePtr.p->m_scanfrag_data.m_rows_expecting
+ + treeNodePtr.p->m_scanfrag_data.m_descendant_keyconfs_received;
conf->fragmentCompleted = treeNodePtr.p->m_scanfrag_data.m_scan_status;
conf->total_len = 0; // Not supported...
sendSignal(requestPtr.p->m_senderRef, GSN_SCAN_FRAGCONF, signal,
ScanFragConf::SignalLength, JBB);
-
if (treeNodePtr.p->m_scanfrag_data.m_scan_status == 2)
{
jam();
@@ -1937,6 +1967,46 @@ Dbspj::scanFrag_cleanup(Ptr<Request> req
{
cleanup_common(requestPtr, treeNodePtr);
}
+
+void
+Dbspj::scanFrag_count_descendant_signal(Signal* signal,
+ Ptr<Request> requestPtr,
+ Ptr<TreeNode> rootPtr,
+ Uint32 globalSignalNo)
+{
+ switch(globalSignalNo){
+ case GSN_LQHKEYCONF:
+ jam();
+ rootPtr.p->m_scanfrag_data.m_descendant_keyconfs_received++;
+ ndbout << "Dbspj::scanFrag_count_descendant_signal() incremented "
+ "m_scanfrag_data.m_descendant_keyconfs_received to "<<
+ rootPtr.p->m_scanfrag_data.m_descendant_keyconfs_received << endl;
+ break;
+ case GSN_LQHKEYREF:
+ jam();
+ rootPtr.p->m_scanfrag_data.m_descendant_keyrefs_received++;
+ ndbout << "Dbspj::scanFrag_count_descendant_signal() incremented "
+ "m_scanfrag_data.m_descendant_keyrefs_received to "<<
+ rootPtr.p->m_scanfrag_data.m_descendant_keyrefs_received << endl;
+ break;
+ case GSN_LQHKEYREQ:
+ jam();
+ rootPtr.p->m_scanfrag_data.m_descendant_keyreqs_sent++;
+ ndbout << "Dbspj::scanFrag_count_descendant_signal() incremented "
+ "m_scanfrag_data.m_descendant_keyreqs_sent to "<<
+ rootPtr.p->m_scanfrag_data.m_descendant_keyreqs_sent << endl;
+ break;
+ default:
+ jam();
+ ndbrequire(false);
+ }
+ if(isScanComplete(rootPtr.p->m_scanfrag_data)){
+ jam();
+ ndbrequire(globalSignalNo!=GSN_LQHKEYREQ);
+ scanFrag_batch_complete(signal, requestPtr, rootPtr);
+ }
+}
+
/**
* END - MODULE SCAN FRAG
*/
@@ -2252,6 +2322,18 @@ error:
return DbspjErr::OutOfSectionMemory;
}
+const Ptr<Dbspj::TreeNode>
+Dbspj::getRoot(TreeNode_list::Head& head)
+{
+ Ptr<TreeNode> rootPtr;
+ const Local_TreeNode_list list(m_treenode_pool, head);
+ const bool found = list.first(rootPtr);
+ ndbassert(found);
+ ndbassert(!rootPtr.isNull());
+ ndbassert(rootPtr.p->m_node_no==0);
+ return rootPtr;
+}
+
/**
* This function takes a pattern and a row and expands it into a section
*/
=== modified file 'storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp'
--- a/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp 2009-06-12 12:01:12 +0000
+++ b/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp 2009-08-07 09:33:27 +0000
@@ -10604,7 +10604,6 @@ void Dbtc::execSCAN_FRAGCONF(Signal* sig
}//if
ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::LQH_ACTIVE);
-
if(scanptr.p->scanState == ScanRecord::CLOSING_SCAN){
jam();
if(status == 0){
@@ -10667,6 +10666,10 @@ void Dbtc::execSCAN_FRAGCONF(Signal* sig
scanFragptr.p->scanFragState = ScanFragRec::QUEUED_FOR_DELIVERY;
scanFragptr.p->stopFragTimer();
+ if(refToMain(signal->header.theSendersBlockRef)==DBSPJ){
+ ndbout << "Dbtc::execSCAN_FRAGCONF() got SCAN_FRAGCONF from DBSPJ "
+ "scanptr.p->m_queued_count=" << scanptr.p->m_queued_count << endl;
+ }
if(scanptr.p->m_queued_count > /** Min */ 0){
jam();
sendScanTabConf(signal, scanptr);
=== modified file 'storage/ndb/src/ndbapi/NdbQueryBuilder.cpp'
--- a/storage/ndb/src/ndbapi/NdbQueryBuilder.cpp 2009-08-03 07:58:08 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryBuilder.cpp 2009-08-07 09:33:27 +0000
@@ -17,7 +17,6 @@
*/
#include "NdbQueryBuilderImpl.hpp"
-#include "NdbQueryOperationImpl.hpp"
#include <ndb_global.h>
#include <Vector.hpp>
@@ -204,10 +203,6 @@ private:
virtual Type getType() const
{ return (index!=NULL) ? PrimaryKeyAccess : UniqueIndexAccess; }
- /** Make an instance for a concrete query.*/
- virtual NdbQueryOperationImpl* makeOperation(NdbQueryImpl& query) const
- { return new NdbQueryLookupOperationImpl(query, *this);}
-
private:
NdbQueryLookupOperationDef m_interface;
const NdbDictionary::Index* const m_index;
@@ -227,10 +222,6 @@ public:
Uint32 ix)
: NdbQueryOperationDefImpl(table,ident,ix)
{};
-
- /** Make an instance for a concrete query.*/
- virtual NdbQueryOperationImpl* makeOperation(NdbQueryImpl& query) const
- { return new NdbQueryScanOperationImpl(query, *this);}
}; // class NdbQueryScanOperationDefImpl
class NdbQueryTableScanOperationDefImpl : public NdbQueryScanOperationDefImpl
@@ -1056,7 +1047,7 @@ NdbQueryIndexScanOperationDefImpl
::materializeRootOperands(NdbOperation& ndbOperation,
const constVoidPtr actualParam[]) const
{
- assert(false); // TODO: Implement this.
+ // TODO: Implement this.
}
void
@@ -1272,12 +1263,10 @@ NdbQueryLookupOperationDefImpl
break;
}
case NdbQueryOperandImpl::Param: // TODO: Implement this
- if(false){
- /**** 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
- }
+ /**** 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:
assert(false);
=== modified file 'storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp 2009-07-31 12:24:15 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryBuilderImpl.hpp 2009-08-07 09:33:27 +0000
@@ -31,7 +31,7 @@
#define QRY_OPERAND_ALREADY_BOUND 4807
#define QRY_DEFINITION_TOO_LARGE 4808
#define QRY_DUPLICATE_COLUMN_IN_PROJ 4809
-
+#define QRY_RESULT_ROW_ALREADY_DEFINED 4810
#ifdef __cplusplus
#include "signaldata/TcKeyReq.hpp"
@@ -46,8 +46,6 @@ class NdbQueryOperationDefImpl;
class NdbParamOperandImpl;
class NdbConstOperandImpl;
class NdbLinkedOperandImpl;
-class NdbQueryOperationImpl;
-class NdbQueryImpl;
/** A buffer for holding serialized data.*/
class Uint32Buffer{
@@ -277,9 +275,6 @@ public:
// Get type of query operation
virtual Type getType() const = 0;
- /** Make an instance for a concrete query.*/
- virtual NdbQueryOperationImpl* makeOperation(NdbQueryImpl& query) const = 0;
-
virtual const NdbQueryOperationDef& getInterface() const = 0;
/** Make a serialized representation of this operation, corresponding to
=== modified file 'storage/ndb/src/ndbapi/NdbQueryOperation.cpp'
--- a/storage/ndb/src/ndbapi/NdbQueryOperation.cpp 2009-08-04 07:40:08 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryOperation.cpp 2009-08-07 09:33:27 +0000
@@ -167,7 +167,7 @@ NdbQueryOperation::setResultRowBuf (
int
NdbQueryOperation::setResultRowRef (
const NdbRecord* rec,
- char* & bufRef,
+ const char* & bufRef,
const unsigned char* result_mask)
{
return m_impl.setResultRowRef(rec, bufRef, result_mask);
@@ -215,8 +215,7 @@ NdbQueryImpl::NdbQueryImpl(NdbTransactio
{
const NdbQueryOperationDefImpl& def = queryDef.getQueryOperation(i);
- NdbQueryOperationImpl* op = def.makeOperation(*this);
- assert(op!=NULL);
+ NdbQueryOperationImpl* op = new NdbQueryOperationImpl(*this, def);
m_operations.push_back(op);
if(def.getQueryOperationIx()==0)
@@ -304,7 +303,16 @@ NdbQueryImpl::getParameter(Uint32 num) c
int
NdbQueryImpl::nextResult(bool fetchAllowed, bool forceSend)
{
- return 1; // FIXME
+#ifdef UNUSED
+ if(!fetchAllowed){
+ for(Uint32 i = 0; i<m_operations.size(); i++){
+ if(!m_operations[i].hasNextInBuffer()){
+ return 2;
+ }
+ }
+ }
+#endif
+ return m_operations[0]->nextResult(fetchAllowed, forceSend);
}
void
@@ -404,55 +412,32 @@ NdbQueryImpl::release(){
}
////////////////////////////////////////////////////
-///////// NdbQueryReceiver methods ///////////
-////////////////////////////////////////////////////
-
-NdbQueryReceiver::NdbQueryReceiver(NdbQueryOperationImpl& owner):
- m_magic(MAGIC),
- m_id(owner.getQuery().getNdbTransaction()->getNdb()->theImpl
- ->theNdbObjectIdMap.map(this)),
- m_owner(owner),
- m_receiver(owner.getQuery().getNdbTransaction()->getNdb())
-{
- m_receiver.init(NdbReceiver::NDB_OPERATION, false, NULL);
-};
-
-NdbQueryReceiver::~NdbQueryReceiver()
-{
- if (m_id != NdbObjectIdMap::InvalidId) {
- m_owner.getQuery().getNdbTransaction()->getNdb()->theImpl
- ->theNdbObjectIdMap.unmap(m_id, this);
- }
-}
-
-bool NdbQueryReceiver::execTRANSID_AI(const Uint32* ptr, Uint32 len)
-{
- m_receiver.execTRANSID_AI(ptr, len);
- return m_owner.execTRANSID_AI();
-}
-
-////////////////////////////////////////////////////
///////// NdbQueryOperationImpl methods ///////////
////////////////////////////////////////////////////
NdbQueryOperationImpl::NdbQueryOperationImpl(
NdbQueryImpl& queryImpl,
- const NdbQueryOperationDefImpl& def,
- Uint32 magic):
- m_magic(magic),
+ const NdbQueryOperationDefImpl& def):
+ m_interface(*this),
+ m_magic(MAGIC),
m_id(queryImpl.getNdbTransaction()->getNdb()->theImpl
->theNdbObjectIdMap.map(this)),
m_operationDef(def),
- /* Initially, a result is only expected for the root operation.*/
- m_pendingResults(def.getQueryOperationIx() == 0 ? 1 : 0),
+ m_parents(def.getNoOfParentOperations()),
+ m_children(def.getNoOfChildOperations()),
+ m_receiver(queryImpl.getNdbTransaction()->getNdb()),
+ m_queryImpl(queryImpl),
+ m_pendingResults(0),
+ m_pendingScanTabConfs(0),
m_userProjection(def.getTable()),
m_resultStyle(Style_None),
- m_queryImpl(queryImpl),
- m_interface(*this),
- m_parents(def.getNoOfParentOperations()),
- m_children(def.getNoOfChildOperations())
+ m_batchBuffer(NULL),
+ m_resultBuffer(NULL),
+ m_resultRef(NULL),
+ m_isRowNull(true)
{
assert(m_id != NdbObjectIdMap::InvalidId);
+ m_receiver.init(NdbReceiver::NDB_OPERATION, false, NULL);
// Fill in operations parent refs, and append it as child of its parents
for (Uint32 p=0; p<def.getNoOfParentOperations(); ++p)
{
@@ -469,6 +454,14 @@ NdbQueryOperationImpl::~NdbQueryOperatio
m_queryImpl.getNdbTransaction()->getNdb()->theImpl
->theNdbObjectIdMap.unmap(m_id, this);
}
+ if(m_batchBuffer){
+ // Check against buffer overun.
+ assert(m_batchBuffer[m_batchByteSize] == 'a' &&
+ m_batchBuffer[m_batchByteSize+1] == 'b' &&
+ m_batchBuffer[m_batchByteSize+2] == 'c' &&
+ m_batchBuffer[m_batchByteSize+3] == 'd');
+ }
+ delete[] m_batchBuffer;
}
@@ -496,6 +489,12 @@ NdbQueryOperationImpl::getChildOperation
return *m_children[i];
}
+const NdbQueryOperationDefImpl&
+NdbQueryOperationImpl::getQueryOperationDef() const
+{
+ return m_operationDef;
+}
+
NdbQueryImpl&
NdbQueryOperationImpl::getQuery() const
{
@@ -530,16 +529,147 @@ NdbQueryOperationImpl::getValue(
}
}
+NdbRecAttr*
+NdbQueryOperationImpl::getValue(
+ const NdbDictionary::Column* column,
+ char* resultBuffer)
+{
+ /* This code will only work for the lookup example in test_spj.cpp.
+ */
+ if(unlikely(m_resultStyle == Style_NdbRecord)){
+ return NULL;
+ }
+ m_resultStyle = Style_NdbRecAttr;
+ if(unlikely(m_userProjection.addColumn(*column) !=0)){
+ return NULL;
+ }
+ return m_receiver.getValue(&NdbColumnImpl::getImpl(*column), resultBuffer);
+}
+
+static bool isSetInMask(const unsigned char* mask, int bitNo){
+ return mask[bitNo>>3] & 1<<(bitNo&7);
+}
+
+int
+NdbQueryOperationImpl::setResultRowBuf (
+ const NdbRecord *rec,
+ char* resBuffer,
+ const unsigned char* result_mask)
+{
+ if (rec->tableId !=
+ static_cast<Uint32>(m_operationDef.getTable().getTableId())){
+ /* The key_record and attribute_record in primary key operation do not
+ belong to the same table.*/
+ return 4287;
+ }
+ if(unlikely(m_resultStyle==Style_NdbRecAttr)){
+ /* Cannot mix NdbRecAttr and NdbRecord methods in one operation. */
+ return 4284;
+ }else if(unlikely(m_resultStyle==Style_NdbRecord)){
+ return QRY_RESULT_ROW_ALREADY_DEFINED;
+ }
+ m_resultStyle = Style_NdbRecord;
+ m_resultBuffer = resBuffer;
+ assert(m_batchBuffer==NULL);
+ for(Uint32 i = 0; i<rec->noOfColumns; i++){
+ if(likely(result_mask==NULL || isSetInMask(result_mask, i))){
+ m_userProjection.addColumn(*m_operationDef.getTable()
+ .getColumn(rec->columns[i].column_no));
+ }
+ }
+ if(getQuery().getQueryOperation(0U).isScan()){
+ // Root operation is a scan.
+ Uint32 batchSize = 0;
+ Uint32 firstBatchSize = 0;
+ m_receiver
+ .calculate_batch_size(0U, // key_size
+ m_operationDef.getTable().getFragmentCount(),
+ batchSize,
+ m_batchByteSize,
+ firstBatchSize,
+ rec);
+ assert(batchSize!=0);
+ assert(firstBatchSize!=0);
+ m_batchBuffer = new char[m_batchByteSize+4];
+ m_receiver.do_setup_ndbrecord(rec,
+ batchSize,
+ 0 /*key_size*/,
+ 0 /*read_range_no*/,
+ rec->m_row_size,
+ m_batchBuffer,
+ m_userProjection.getColumnCount());
+ }else{
+ m_batchByteSize = rec->m_row_size + 4;
+ m_batchBuffer = new char[m_batchByteSize+4];
+ m_receiver.m_using_ndb_record = true;
+ m_receiver.getValues(rec, m_batchBuffer);
+ }
+ /* To be able to check for buffer overrun.*/
+ m_batchBuffer[m_batchByteSize] = 'a';
+ m_batchBuffer[m_batchByteSize+1] = 'b';
+ m_batchBuffer[m_batchByteSize+2] = 'c';
+ m_batchBuffer[m_batchByteSize+3] = 'd';
+ return 0;
+}
+
+int
+NdbQueryOperationImpl::setResultRowRef (
+ const NdbRecord* rec,
+ const char* & bufRef,
+ const unsigned char* result_mask)
+{
+ m_resultRef = &bufRef;
+ return setResultRowBuf(rec, NULL, result_mask);
+}
+
+int
+NdbQueryOperationImpl::nextResult(bool fetchAllowed, bool forceSend){
+ assert(!forceSend); // FIXME
+ const NdbQueryOperationDefImpl::Type opType
+ = getQueryOperationDef().getType();
+ const bool isLookup = (opType == NdbQueryOperationDefImpl::PrimaryKeyAccess ||
+ opType == NdbQueryOperationDefImpl::UniqueIndexAccess);
+
+ const char* buff = NULL;
+ if(m_receiver.nextResult()){
+ buff = m_receiver.get_row();
+ }else if(m_operationDef.getQueryOperationIx()==0){
+ // Root operation.
+ if(isLookup){
+ return 1; // No more tuples to scan.
+ }else if(fetchAllowed){
+ assert(false); // FIXME
+ }else{
+ return 2; // There are no more cached records in NdbApi
+ }
+ }else{
+ // Non-root operation
+ setNullRowDescendants();
+ return 2; // Dummy return value.
+ }
+ assert(buff!=NULL);
+ for(Uint32 i = 0; i<getNoOfChildOperations(); i++){
+ // For now, only the root can be a scan.
+ getChildOperation(i).nextResult(false, false);
+ }
+ if(m_resultRef!=NULL){
+ *m_resultRef = buff;
+ }else{
+ memcpy(m_resultBuffer, buff, m_receiver.m_record.m_ndb_record->m_row_size);
+ }
+ return 0;
+}
+
bool
NdbQueryOperationImpl::isRowNULL() const
{
- return true; // FIXME
+ return m_isRowNull;
}
bool
NdbQueryOperationImpl::isRowChanged() const
{
- return false; // FIXME
+ return true;
}
// Constructor.
@@ -607,45 +737,20 @@ NdbQueryOperationImpl::UserProjection::s
return 0;
}
-bool
-NdbQueryOperationImpl::execTCKEYREF(NdbApiSignal* aSignal){
- ndbout << "NdbQueryOperationImpl::execTCKEYREF(): *this="
- << *this << endl;
- m_pendingResults--;
- if(m_pendingResults==0){
- /* This operation is complete. Check if the query is also complete.*/
- return m_queryImpl.incPendingOperations(-1);
- }else if(m_pendingResults==-1){
- /* This happens because we received results for the child before those
- * of the parent. This operation will be set as complete again when the
- * TRANSID_AI for the parent arrives.*/
- m_queryImpl.incPendingOperations(1);
- }
- return false;
-}
-
-//
-// NdbQueryLookupOperationImpl method definitions.
-//
-
#define POS_IN_PARAM(field) \
(offsetof(QueryNodeParameters, field)/sizeof(Uint32))
#define POS_IN_LOOKUP_PARAM(field) \
(offsetof(QN_LookupParameters, field)/sizeof(Uint32))
-int NdbQueryLookupOperationImpl::prepareSend(Uint32Buffer& serializedParams)
-{
- const NdbQueryOperationDefImpl::Type opType
- = getQueryOperationDef().getType();
- assert(opType == NdbQueryOperationDefImpl::PrimaryKeyAccess ||
- opType == NdbQueryOperationDefImpl::UniqueIndexAccess);
- m_queryReceiver.getReceiver().prepareSend();
+int NdbQueryOperationImpl::prepareSend(Uint32Buffer& serializedParams)
+{
+ m_receiver.prepareSend();
Uint32Slice lookupParams(serializedParams, serializedParams.getSize());
Uint32 requestInfo = 0;
lookupParams.get(POS_IN_PARAM(requestInfo)) = 0;
- lookupParams.get(POS_IN_PARAM(resultData)) = m_queryReceiver.getId();
+ lookupParams.get(POS_IN_PARAM(resultData)) = m_id;
Uint32Slice optional(lookupParams, POS_IN_LOOKUP_PARAM(optional));
int optPos = 0;
@@ -653,7 +758,7 @@ int NdbQueryLookupOperationImpl::prepare
//printf("operation has %d params\n", getQueryOperationDef().getNoOfParameters());
// SPJ block assume PARAMS to be supplied before ATTR_LIST
- if (false && getQueryOperationDef().getNoOfParameters() > 0)
+ if (getQueryOperationDef().getNoOfParameters() > 0)
{
int size = 0;
requestInfo |= DABits::PI_KEY_PARAMS;
@@ -680,16 +785,31 @@ int NdbQueryLookupOperationImpl::prepare
}
lookupParams.get(POS_IN_PARAM(requestInfo)) = requestInfo;
+ // TODO: Implement for scans as well.
QueryNodeParameters::setOpLen(lookupParams.get(POS_IN_PARAM(len)),
- QueryNodeParameters::QN_LOOKUP,
+ isScan()
+ ?QueryNodeParameters::QN_SCAN_FRAG
+ :QueryNodeParameters::QN_LOOKUP,
lookupParams.getSize());
-
+ if(m_operationDef.getQueryOperationIx()==0)
+ {
+ if(isScan())
+ {
+ m_pendingResults = 0;
+ m_pendingScanTabConfs
+ = getQueryOperationDef().getTable().getFragmentCount();
+ }
+ else
+ {
+ m_pendingResults = 1;
+ }
+ }
if(unlikely(lookupParams.isMaxSizeExceeded())){
return QRY_DEFINITION_TOO_LARGE; // Query definition too large.
}
#ifdef TRACE_SERIALIZATION
ndbout << "Serialized params for node "
- << getQueryOperationDef().getQueryOperationIx() << " : ";
+ << m_operationDef.getQueryOperationIx() << " : ";
for(Uint32 i = 0; i < lookupParams.getSize(); i++){
char buf[12];
sprintf(buf, "%.8x", lookupParams.get(i));
@@ -701,32 +821,34 @@ int NdbQueryLookupOperationImpl::prepare
}
-void NdbQueryLookupOperationImpl::release(){
- m_queryReceiver.getReceiver().release();
+void NdbQueryOperationImpl::release(){
+ m_receiver.release();
}
bool
-NdbQueryLookupOperationImpl::execTRANSID_AI(){
+NdbQueryOperationImpl::execTRANSID_AI(const Uint32* ptr, Uint32 len){
ndbout << "NdbQueryOperationImpl::execTRANSID_AI(): *this="
<< *this << endl;
+ // Process result values.
+ m_receiver.execTRANSID_AI(ptr, len);
m_pendingResults--;
/* Receiving this message means that each child has been instantiated
* one more. Therefore, increment the pending message count for the children.
*/
for(Uint32 i = 0; i<getNoOfChildOperations(); i++){
- int& childPendingResults = getPendingResults(getChildOperation(i));
- childPendingResults++;
- if(childPendingResults == 0){
- /* This child appears to be complete. Therefore decrement total count
- * of pending operations.*/
- m_queryImpl.incPendingOperations(-1);
- }else if(childPendingResults == 1){
+ if(getChildOperation(i).isComplete()){
/* This child appeared to be complete prior to receiving this message,
* but now we know that there will be
* an extra instance. Therefore, increment total count of pending
* operations.*/
m_queryImpl.incPendingOperations(1);
+ }
+ getChildOperation(i).m_pendingResults++;
+ if(getChildOperation(i).isComplete()){
+ /* This child appears to be complete. Therefore decrement total count
+ * of pending operations.*/
+ m_queryImpl.incPendingOperations(-1);
}
}
@@ -743,224 +865,70 @@ NdbQueryLookupOperationImpl::execTRANSID
}
-NdbQueryLookupOperationImpl
-::NdbQueryLookupOperationImpl(NdbQueryImpl& queryImpl,
- const NdbQueryOperationDefImpl& def):
- NdbQueryOperationImpl(queryImpl, def, MAGIC_LOOKUP),
- m_queryReceiver(*this)
-{
-}
-
-NdbRecAttr*
-NdbQueryLookupOperationImpl::getValue(
- const NdbDictionary::Column* column,
- char* resultBuffer)
-{
- /* This code will only work for the lookup example in test_spj.cpp.
- */
- if(unlikely(m_resultStyle == Style_NdbRecord)){
- return NULL;
- }
- m_resultStyle = Style_NdbRecAttr;
- if(unlikely(m_userProjection.addColumn(*column) !=0)){
- return NULL;
+bool
+NdbQueryOperationImpl::execTCKEYREF(NdbApiSignal* aSignal){
+ ndbout << "NdbQueryOperationImpl::execTCKEYREF(): *this="
+ << *this << endl;
+ if(isComplete()){
+ /* This happens because we received results for the child before those
+ * of the parent. This operation will be set as complete again when the
+ * TRANSID_AI for the parent arrives.*/
+ m_queryImpl.incPendingOperations(1);
+ }
+ m_pendingResults--;
+ if(isComplete()){
+ /* This operation is complete. Check if the query is also complete.*/
+ return m_queryImpl.incPendingOperations(-1);
}
- return m_queryReceiver.getReceiver().getValue(&NdbColumnImpl::getImpl(*column), resultBuffer);
-}
-
-static bool isSetInMask(const unsigned char* mask, int bitNo){
- return mask[bitNo>>3] & 1<<(bitNo&7);
+ return false;
}
-int
-NdbQueryLookupOperationImpl::setResultRowBuf (
- const NdbRecord *rec,
- char* resBuffer,
- const unsigned char* result_mask)
+void
+NdbQueryOperationImpl::execSCAN_TABCONF(Uint32 tcPtrI,
+ Uint32 rowCount)
{
- if (rec->tableId !=
- static_cast<Uint32>(getQueryOperationDef().getTable().getTableId())){
- /* The key_record and attribute_record in primary key operation do not
- belong to the same table.*/
- return 4287;
- }
- if(unlikely(m_resultStyle==Style_NdbRecAttr)){
- /* Cannot mix NdbRecAttr and NdbRecord methods in one operation. */
- return 4284;
- }
- m_resultStyle = Style_NdbRecord;
- m_queryReceiver.getReceiver().m_using_ndb_record = true;
- m_queryReceiver.getReceiver().getValues(rec, resBuffer);
- for(Uint32 i = 0; i<rec->noOfColumns; i++){
- if(likely(result_mask==NULL || isSetInMask(result_mask, i))){
- m_userProjection.addColumn(*getQueryOperationDef().getTable()
- .getColumn(rec->columns[i].column_no));
+ ndbout << "NdbQueryOperationImpl::execSCAN_TABCONF(): tcPtrI="
+ << tcPtrI << " rowCount=" << rowCount
+ << " *this=" << *this << endl;
+ // For now, only the root operation may be a scan.
+ assert(m_operationDef.getQueryOperationIx()==0);
+ assert(m_pendingScanTabConfs>0);
+ m_pendingScanTabConfs--;
+ if(tcPtrI != RNIL || rowCount > 0){
+ m_receiver.execSCANOPCONF(tcPtrI, 0, rowCount);
+ m_pendingResults += rowCount;
+#ifdef UNUSED
+ for(Uint32 i = 0; i<getNoOfChildOperations(); i++){
+ if(getChildOperation(i).isComplete()){
+ /* This child appeared to be complete prior to receiving this message,
+ * but now we know that there will be
+ * extra instances. Therefore, increment total count of pending
+ * operations.*/
+ m_queryImpl.incPendingOperations(1);
+ }
+ getChildOperation(i).m_pendingResults += rowCount;
+ if(getChildOperation(i).isComplete()){
+ /* This child appears to be complete. Therefore decrement total count
+ * of pending operations.*/
+ m_queryImpl.incPendingOperations(-1);
+ }
}
+#endif
}
- return 0;
-}
-
-int
-NdbQueryLookupOperationImpl::setResultRowRef (
- const NdbRecord* rec,
- char* & bufRef,
- const unsigned char* result_mask)
-{
-/***
- if (rec->tableId != m_table->tableId)
- {
- setErrorCode(4287);
- return -1;
- }
-***/
- return 0; // FIXME
-}
-
-
-//
-// NdbQueryScanOperationImpl method definitions.
-//
-
-NdbQueryScanOperationImpl
-::NdbQueryScanOperationImpl(NdbQueryImpl& queryImpl,
- const NdbQueryOperationDefImpl& def):
- NdbQueryOperationImpl(queryImpl, def, MAGIC_SCAN)
-{}
-
-
-NdbQueryScanOperationImpl::~NdbQueryScanOperationImpl()
-{
- for(int i = 0; i<m_queryReceivers.size(); i++){
- delete m_queryReceivers[i];
+ if(isComplete()){
+ /* This operation appears to be complete*/
+ m_queryImpl.incPendingOperations(-1);
}
}
-NdbRecAttr*
-NdbQueryScanOperationImpl::getValue(
- const NdbDictionary::Column* column,
- char* resultBuffer)
-{
- assert(false);
- return 0; // FIXME
-}
-
-int
-NdbQueryScanOperationImpl::setResultRowBuf (
- const NdbRecord *rec,
- char* resBuffer,
- const unsigned char* result_mask)
-{
- assert(false);
- return 0; // FIXME
-}
-
-int
-NdbQueryScanOperationImpl::setResultRowRef (
- const NdbRecord* rec,
- char* & bufRef,
- const unsigned char* result_mask)
-{
- if (rec->tableId !=
- static_cast<Uint32>(getQueryOperationDef().getTable().getTableId())){
- /* The key_record and attribute_record in primary key operation do not
- belong to the same table.*/
- return 4287;
- }
- if(unlikely(m_resultStyle==Style_NdbRecAttr)){
- /* Cannot mix NdbRecAttr and NdbRecord methods in one operation. */
- return 4284;
- }
- m_resultStyle = Style_NdbRecord;
- // FIXME
- // m_queryReceiver.getReceiver().m_using_ndb_record = true;
- // m_queryReceiver.getReceiver().getValues(rec, resBuffer);
- for(Uint32 i = 0; i<rec->noOfColumns; i++){
- if(likely(result_mask==NULL || isSetInMask(result_mask, i))){
- m_userProjection.addColumn(*getQueryOperationDef().getTable()
- .getColumn(rec->columns[i].column_no));
- }
- }
- return 0;
-}
-
-int NdbQueryScanOperationImpl::prepareSend(Uint32Buffer& serializedParams)
-{
- const NdbQueryOperationDefImpl::Type opType
- = getQueryOperationDef().getType();
- assert(opType == NdbQueryOperationDefImpl::TableScan ||
- opType == NdbQueryOperationDefImpl::OrderedIndexScan);
-
- //m_queryReceiver.getReceiver().prepareSend();
- Uint32Slice lookupParams(serializedParams, serializedParams.getSize());
- Uint32 requestInfo = 0;
- lookupParams.get(POS_IN_PARAM(requestInfo)) = 0;
- lookupParams.get(POS_IN_PARAM(resultData)) = ptr2int();
- Uint32Slice optional(lookupParams, POS_IN_LOOKUP_PARAM(optional));
-
- int optPos = 0;
-
- //printf("operation has %d params\n", getQueryOperationDef().getNoOfParameters());
-
- // SPJ block assume PARAMS to be supplied before ATTR_LIST
- if (false && getQueryOperationDef().getNoOfParameters() > 0)
- {
- int size = 0;
- requestInfo |= DABits::PI_KEY_PARAMS;
- Uint32Slice keyParam(optional, optPos);
-
- // 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;
- }
-
- if (true)
- {
- requestInfo |= DABits::PI_ATTR_LIST;
-
- const int error = m_userProjection.serialize(Uint32Slice(optional, optPos));
- if(error!=0){
- return error;
- }
- }
- lookupParams.get(POS_IN_PARAM(requestInfo)) = requestInfo;
-
- QueryNodeParameters::setOpLen(lookupParams.get(POS_IN_PARAM(len)),
- QueryNodeParameters::QN_SCAN_FRAG,
- lookupParams.getSize());
-
- if(unlikely(lookupParams.isMaxSizeExceeded())){
- return QRY_DEFINITION_TOO_LARGE; // Query definition too large.
- }
-#ifdef TRACE_SERIALIZATION
- ndbout << "Serialized params for node "
- << getQueryOperationDef().getQueryOperationIx() << " : ";
- for(Uint32 i = 0; i < lookupParams.getSize(); i++){
- char buf[12];
- sprintf(buf, "%.8x", lookupParams.get(i));
- ndbout << buf << " ";
+void
+NdbQueryOperationImpl::setNullRowDescendants(){
+ m_isRowNull = true;
+ for(Uint32 i = 0; i<getNoOfChildOperations(); i++){
+ getChildOperation(i).setNullRowDescendants();
}
- ndbout << endl;
-#endif
- return 0;
}
-
-void NdbQueryScanOperationImpl::release(){
- assert(false);
-}
-
-
-bool
-NdbQueryScanOperationImpl::execTRANSID_AI(){
- assert(false);
-}
-
-
/** For debugging.*/
NdbOut& operator<<(NdbOut& out, const NdbQueryOperationImpl& op){
out << "[ this: " << &op
@@ -981,4 +949,4 @@ NdbOut& operator<<(NdbOut& out, const Nd
// Compiler settings require explicit instantiation.
template class Vector<NdbQueryOperationImpl*>;
-template class Vector<NdbQueryReceiver*>;
+
=== modified file 'storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp'
--- a/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp 2009-08-04 07:40:08 +0000
+++ b/storage/ndb/src/ndbapi/NdbQueryOperationImpl.hpp 2009-08-07 09:33:27 +0000
@@ -28,38 +28,33 @@
#include <Vector.hpp>
#include <NdbOut.hpp>
-//class NdbQueryLookupOperationDefImpl;
-//class NdbQueryScanOperationDefImpl;
-
-#ifdef UNUSED
template<Uint32 magic>
class NdbMappable{
public:
+
Uint32 getId() const {return m_id;}
+
bool checkMagicNumber() const {return m_magic == magic;}
protected:
+
explicit NdbMappable(const Ndb& ndb):
m_magic(magic),
m_id(ndb.theImpl->theNdbObjectIdMap.map(this)),
m_ndb(ndb)
{}
+
virtual ~NdbMappable(){
if (m_id != NdbObjectIdMap::InvalidId) {
m_ndb.theImpl->theNdbObjectIdMap.unmap(m_id, this);
}
}
-}
+
private:
const Uint32 m_magic;
const Uint32 m_id;
const Ndb& m_ndb;
};
-#endif
-/** This class is the internal implementation of NdbQuery. Unlike NdbQuery
- * it should not be exposed to application developers (NdbAPI users).
- * Like NdbQuery, this class represents an instantiation of a query (as
- * defined by NdbQueryDefImpl) for a given transaction and set of actual
- * parameters. */
+
class NdbQueryImpl {
private:
// Only constructable from factory ::buildQuery();
@@ -119,7 +114,7 @@ public:
Uint32 ptr2int() const
{ return m_id; }
-
+
const NdbQuery& getInterface() const
{ return m_interface; }
@@ -166,48 +161,6 @@ private:
const NdbQueryDefImpl& m_queryDef;
}; // class NdbQueryImpl
-/** This class represents a context for processing TRANSID_AI messages.
- * Scan operation need to differentiate between messages comming from
- * different data nodes. Therefore, a separate mappable class is needed.*/
-class NdbQueryReceiver{
-public:
- /** Unique class ID.*/
- STATIC_CONST( MAGIC = 0xdead8888);
-
- explicit NdbQueryReceiver(NdbQueryOperationImpl& owner);
-
- ~NdbQueryReceiver();
-
- Uint32 getId() const {return m_id;}
-
- bool checkMagicNumber() const {return m_magic == MAGIC;}
-
- bool execTRANSID_AI(const Uint32* ptr, Uint32 len);
-
- bool execTCKEYREF(NdbApiSignal* aSignal);
-
- NdbReceiver& getReceiver(){return m_receiver;}
-
- const NdbReceiver& getReceiver() const {return m_receiver;}
-
- NdbTransaction* getNdbTransaction() const;
-
- NdbOperation* getNdbOperation() const;
-private:
- /** For verifying pointers to instances of this class.*/
- const Uint32 m_magic;
- /** Id to be used in global object map.*/
- const Uint32 m_id;
- /** Operation to which this instance belong.*/
- NdbQueryOperationImpl& m_owner;
- /** For extracting tuple values.*/
- NdbReceiver m_receiver;
- /** Copy not allowed.*/
- NdbQueryReceiver(const NdbQueryReceiver&);
- /** Copy not allowed.*/
- NdbQueryReceiver& operator=(const NdbQueryReceiver&);
-};
-
/** This class contains data members for NdbQueryOperation, such that these
* do not need to exposed in NdbQueryOperation.hpp. This class may be
@@ -217,14 +170,12 @@ class NdbQueryOperationImpl {
/** For debugging.*/
friend NdbOut& operator<<(NdbOut& out, const NdbQueryOperationImpl&);
public:
- STATIC_CONST (MAGIC_LOOKUP = 0xfade1234);
- STATIC_CONST (MAGIC_SCAN = 0xfade4321);
+ STATIC_CONST (MAGIC = 0xfade1234);
explicit NdbQueryOperationImpl(NdbQueryImpl& queryImpl,
- const NdbQueryOperationDefImpl& def,
- Uint32 magic);
- virtual ~NdbQueryOperationImpl() = 0;
+ const NdbQueryOperationDefImpl& def);
+ ~NdbQueryOperationImpl();
Uint32 getNoOfParentOperations() const;
NdbQueryOperationImpl& getParentOperation(Uint32 i) const;
@@ -232,30 +183,38 @@ public:
Uint32 getNoOfChildOperations() const;
NdbQueryOperationImpl& getChildOperation(Uint32 i) const;
- const NdbQueryOperationDefImpl& getQueryOperationDef() const
- {return m_operationDef;}
+ const NdbQueryOperationDefImpl& getQueryOperationDef() const;
// Get the entire query object which this operation is part of
NdbQueryImpl& getQuery() const;
NdbRecAttr* getValue(const char* anAttrName, char* resultBuffer);
NdbRecAttr* getValue(Uint32 anAttrId, char* resultBuffer);
- virtual NdbRecAttr* getValue(const NdbDictionary::Column*,
- char* resultBuffer) = 0;
+ NdbRecAttr* getValue(const NdbDictionary::Column*, char* resultBuffer);
- virtual int setResultRowBuf (const NdbRecord *rec,
- char* resBuffer,
- const unsigned char* result_mask) = 0;
-
- virtual int setResultRowRef (const NdbRecord* rec,
- char* & bufRef,
- const unsigned char* result_mask) = 0;
+ int setResultRowBuf (const NdbRecord *rec,
+ char* resBuffer,
+ const unsigned char* result_mask);
+
+ int setResultRowRef (const NdbRecord* rec,
+ const char* & bufRef,
+ const unsigned char* result_mask);
bool isRowNULL() const; // Row associated with Operation is NULL value?
bool isRowChanged() const; // Prev ::nextResult() on NdbQuery retrived a new
// value for this NdbQueryOperation
+ /** Fetch next result row.
+ * @see NdbQuery::nextResult */
+ int nextResult(bool fetchAllowed, bool forceSend);
+
+#ifdef UNUSED
+ /** Returns true if this operation has more resulst available in its buffers
+ * (i.e. *without�� doing a fetch.)*/
+ bool hasNextInBuffer() const {return m_receiver.nextResult()};
+#endif
+
/** Returns an I-value for the NdbReceiver object that shall receive results
* for this operation.
* @return The I-value.
@@ -266,35 +225,44 @@ public:
/** Process result data for this operation. Return true if query complete.*/
- virtual bool execTRANSID_AI() = 0;
+ bool execTRANSID_AI(const Uint32* ptr, Uint32 len);
/** Process absence of result data for this operation.
* Return true if query complete.*/
bool execTCKEYREF(NdbApiSignal* aSignal);
+ /** Scan batch is complete.*/
+ void execSCAN_TABCONF(Uint32 tcPtrI, Uint32 rowCount);
+
/** Prepare for execution.
* @return possible error code.*/
- virtual int prepareSend(Uint32Buffer& serializedParams) = 0;
+ int prepareSend(Uint32Buffer& serializedParams);
/** Release NdbReceiver objects.*/
- virtual void release() = 0;
+ void release();
+ /* TODO: Remove this method. Only needed in spj_test.cpp.*/
/** Return I-value for putting in object map.*/
Uint32 ptr2int() const {
return m_id;
}
/** Verify magic number.*/
- bool checkMagicNumber() const {
- /*This could also have been a vitual function, but invoking a vitual
- function on an object of uncertain type is unsafe.*/
- return m_magic == MAGIC_LOOKUP || m_magic == MAGIC_SCAN;
+ bool checkMagicNumber() const {
+ return m_magic == MAGIC;
}
- /** Check if operation is complete.
- * For doing sanity check on internal state.*/
+ /** Check if operation is complete. */
bool isComplete() const {
- return m_pendingResults==0;
+ return m_pendingResults==0 && m_pendingScanTabConfs==0;
+ }
+
+ /** Return true if this operation is a scan.*/
+ bool isScan() const {
+ return getQueryOperationDef().getType()
+ == NdbQueryOperationDefImpl::TableScan ||
+ getQueryOperationDef().getType()
+ == NdbQueryOperationDefImpl::OrderedIndexScan;
}
const NdbQueryOperation& getInterface() const
@@ -302,7 +270,7 @@ public:
NdbQueryOperation& getInterface()
{ return m_interface; }
-protected:
+private:
/** This class represents a projection that shall be sent to the
* application.*/
class UserProjection{
@@ -319,6 +287,9 @@ protected:
* @return Possible error code.*/
int serialize(Uint32Slice dst) const;
+ /** Get number of columns.*/
+ int getColumnCount() const {return m_columnCount;}
+
private:
/** The columns that consitutes the projection.*/
const NdbDictionary::Column* m_columns[MAX_ATTRIBUTES_IN_TABLE];
@@ -335,7 +306,8 @@ protected:
int m_maxColNo;
}; // class UserProjection
- // TODO: Remove this.
+ /** Interface for the application developer.*/
+ NdbQueryOperation m_interface;
/** For verifying pointers to this class.*/
const Uint32 m_magic;
/** I-value for object maps.*/
@@ -343,130 +315,44 @@ protected:
/** The (transaction independent ) definition from which this instance
* was created.*/
const NdbQueryOperationDefImpl& m_operationDef;
+ /* TODO: replace m_children and m_parents with navigation via
+ * m_operationDef.getParentOperation() etc.*/
+ /** Parents of this operation.*/
+ Vector<NdbQueryOperationImpl*> m_parents;
+ /** Children of this operation.*/
+ Vector<NdbQueryOperationImpl*> m_children;
+ /** For processing results from this operation.*/
+ NdbReceiver m_receiver;
+ /** NdbQuery to which this operation belongs. */
+ NdbQueryImpl& m_queryImpl;
/** Number of pending TCKEYREF or TRANSID_AI messages for this operation.*/
int m_pendingResults;
+ /** Number of pending SCAN_TABCONF messages for this operation.*/
+ int m_pendingScanTabConfs;
/** Projection to be sent to the application.*/
UserProjection m_userProjection;
/** NdbRecord and old style result retrieval may not be combined.*/
- enum{
+ enum {
Style_None, // Not set yet.
Style_NdbRecord, // Use old style result retrieval.
Style_NdbRecAttr, // Use NdbRecord.
} m_resultStyle;
- /** NdbQuery to which this operation belongs. */
- NdbQueryImpl& m_queryImpl;
-
- /** In some places we need to access
- * NdbQueryOperationImpl::m_PendingResults without knowing the run-time
- * class of the NdbQueryOperationImpl instance. C++ forbids accessing
- * protected non-static members from a derived class via a pointer or
- * reference to the base class.*/
- static int& getPendingResults(NdbQueryOperationImpl& impl)
- { return impl.m_pendingResults;}
-private:
-
- /** Interface for the application developer.*/
- NdbQueryOperation m_interface;
- /* TODO: replace m_children and m_parents with navigation via
- * m_operationDef.getParentOperation() etc.*/
- /** Parents of this operation.*/
- Vector<NdbQueryOperationImpl*> m_parents;
- /** Children of this operation.*/
- Vector<NdbQueryOperationImpl*> m_children;
+ /** For temporary storing one result batch.*/
+ char* m_batchBuffer;
+ /** Buffer for final storage of result.*/
+ char* m_resultBuffer;
+ /** Pointer to application pointer that should be set to point to the
+ * current row.
+ * @see NdbQueryOperationImpl::setResultRowRef */
+ const char** m_resultRef;
+ /** True if this operation gave no result for the current row.*/
+ bool m_isRowNull;
+ /** Batch size for scans or lookups with scan parents.*/
+ Uint32 m_batchByteSize;
+ /** Set m_isRowNull for this operation and all its descendants.*/
+ void setNullRowDescendants();
}; // class NdbQueryOperationImpl
-class NdbQueryLookupOperationImpl: public NdbQueryOperationImpl{
-public:
- explicit
- NdbQueryLookupOperationImpl(NdbQueryImpl& queryImpl,
- const NdbQueryOperationDefImpl& def);
-
- virtual ~NdbQueryLookupOperationImpl(){}
-
- /** Process result data for this operation. Return true if query complete.*/
- virtual bool execTRANSID_AI();
-
- /** Prepare for execution.
- * @return possible error code.*/
- virtual int prepareSend(Uint32Buffer& serializedParams);
-
- /** Release NdbReceiver objects.*/
- virtual void release();
-
- /** Verify magic number.*/
- bool checkMagicNumber() const {
- return m_magic == MAGIC_LOOKUP;
- }
-
- virtual NdbRecAttr* getValue(const NdbDictionary::Column*,
- char* resultBuffer);
-
- virtual int setResultRowBuf (const NdbRecord *rec,
- char* resBuffer,
- const unsigned char* result_mask);
-
- virtual int setResultRowRef (const NdbRecord* rec,
- char* & bufRef,
- const unsigned char* result_mask);
-
-private:
- /** For processing results from this operation.*/
- NdbQueryReceiver m_queryReceiver;
-
-}; // class NdbQueryLookupOperationImpl
-
-class NdbQueryScanOperationImpl: public NdbQueryOperationImpl{
-public:
- explicit
- NdbQueryScanOperationImpl(NdbQueryImpl& queryImpl,
- const NdbQueryOperationDefImpl& def);
-
- virtual ~NdbQueryScanOperationImpl();
-
- /** Process result data for this operation. Return true if query complete.*/
- virtual bool execTRANSID_AI();
-
- /** Prepare for execution.
- * @return possible error code.*/
- virtual int prepareSend(Uint32Buffer& serializedParams);
-
- /** Release NdbReceiver objects.*/
- virtual void release();
-
- /** Verify magic number.*/
- bool checkMagicNumber() const {
- return m_magic == MAGIC_SCAN;
- }
-
- virtual NdbRecAttr* getValue(const NdbDictionary::Column*,
- char* resultBuffer);
-
- virtual int setResultRowBuf (const NdbRecord *rec,
- char* resBuffer,
- const unsigned char* result_mask);
-
- virtual int setResultRowRef (const NdbRecord* rec,
- char* & bufRef,
- const unsigned char* result_mask);
-private:
- Vector<NdbQueryReceiver*> m_queryReceivers;
-}; // class NdbQueryScanOperationImpl
-
-inline NdbTransaction*
-NdbQueryReceiver::getNdbTransaction() const
-{
- return m_owner.getQuery().getNdbTransaction();
-}
-
-inline bool
-NdbQueryReceiver::execTCKEYREF(NdbApiSignal* aSignal){
- return m_owner.execTCKEYREF(aSignal);
-}
-
-inline NdbOperation*
-NdbQueryReceiver::getNdbOperation() const {
- return m_owner.getQuery().getNdbOperation();
-}
#endif
=== modified file 'storage/ndb/src/ndbapi/NdbReceiver.cpp'
--- a/storage/ndb/src/ndbapi/NdbReceiver.cpp 2009-06-25 09:13:50 +0000
+++ b/storage/ndb/src/ndbapi/NdbReceiver.cpp 2009-08-07 09:33:27 +0000
@@ -146,7 +146,7 @@ NdbReceiver::calculate_batch_size(Uint32
Uint32& batch_size,
Uint32& batch_byte_size,
Uint32& first_batch_size,
- const NdbRecord *record)
+ const NdbRecord *record) const
{
TransporterFacade *tp= m_ndb->theImpl->m_transporter_facade;
Uint32 max_scan_batch_size= tp->get_scan_batch_size();
=== modified file 'storage/ndb/src/ndbapi/NdbTransactionScan.cpp'
--- a/storage/ndb/src/ndbapi/NdbTransactionScan.cpp 2009-05-26 18:53:34 +0000
+++ b/storage/ndb/src/ndbapi/NdbTransactionScan.cpp 2009-08-07 09:33:27 +0000
@@ -32,7 +32,7 @@
#include <signaldata/ScanTab.hpp>
#include <NdbOut.hpp>
-
+#include <NdbQueryOperationImpl.hpp>
/***************************************************************************
* int receiveSCAN_TABREF(NdbApiSignal* aSignal)
@@ -110,10 +110,21 @@ NdbTransaction::receiveSCAN_TABCONF(NdbA
NdbReceiver* tOp = theNdb->void2rec(tPtr);
if (tOp && tOp->checkMagicNumber())
{
- if (tcPtrI == RNIL && opCount == 0)
- theScanningOp->receiver_completed(tOp);
- else if (tOp->execSCANOPCONF(tcPtrI, totalLen, opCount))
- theScanningOp->receiver_delivered(tOp);
+ NdbOperation* const owner = static_cast<NdbOperation*>(tOp->m_owner);
+ if(owner->checkMagicNumber()==0 && owner->m_isLinked)
+ {
+ assert(len==3);
+ owner->m_queryImpl->getQueryOperation(0u)
+ .execSCAN_TABCONF(tcPtrI, opCount);
+ }
+ else
+ {
+ if (tcPtrI == RNIL && opCount == 0)
+ theScanningOp->receiver_completed(tOp);
+ else if (tOp->execSCANOPCONF(tcPtrI, totalLen, opCount))
+ theScanningOp->receiver_delivered(tOp);
+
+ }
}
}
return 0;
=== modified file 'storage/ndb/src/ndbapi/Ndbif.cpp'
--- a/storage/ndb/src/ndbapi/Ndbif.cpp 2009-08-04 07:40:08 +0000
+++ b/storage/ndb/src/ndbapi/Ndbif.cpp 2009-08-07 09:33:27 +0000
@@ -400,14 +400,14 @@ Ndb::handleReceivedSignal(NdbApiSignal*
tFirstDataPtr = int2void(tFirstData);
if (tFirstDataPtr){
NdbReceiver* const tRec = void2rec(tFirstDataPtr);
- NdbQueryReceiver* const queryReceiver
- = reinterpret_cast<NdbQueryReceiver*>(tFirstDataPtr);
+ NdbQueryOperationImpl* const queryOpImpl
+ = reinterpret_cast<NdbQueryOperationImpl*>(tFirstDataPtr);
const bool isReceiver = tRec->checkMagicNumber();
- if(!isReceiver && !queryReceiver->checkMagicNumber()){
+ if(!isReceiver && !queryOpImpl->checkMagicNumber()){
return;
}
tCon = isReceiver ? tRec->getTransaction()
- : queryReceiver->getNdbTransaction();
+ : queryOpImpl->getQuery().getNdbTransaction();
if((tCon!=NULL) &&
tCon->checkState_TransId(((const TransIdAI*)tDataPtr)->transId)){
Uint32 com;
@@ -415,7 +415,7 @@ Ndb::handleReceivedSignal(NdbApiSignal*
if(isReceiver){
com = tRec->execTRANSID_AI(ptr[0].p, ptr[0].sz);
}else{
- com = queryReceiver->execTRANSID_AI(ptr[0].p, ptr[0].sz);
+ com = queryOpImpl->execTRANSID_AI(ptr[0].p, ptr[0].sz);
}
} else {
assert(isReceiver);
@@ -526,8 +526,8 @@ Ndb::handleReceivedSignal(NdbApiSignal*
const bool isNdbOperation =
void2rec(tFirstDataPtr)->checkMagicNumber();
- NdbQueryReceiver* const queryReceiver
- = reinterpret_cast<NdbQueryReceiver*>(tFirstDataPtr);
+ NdbQueryOperationImpl* const queryOpImpl
+ = reinterpret_cast<NdbQueryOperationImpl*>(tFirstDataPtr);
if (isNdbOperation) {
tOp = void2rec_op(tFirstDataPtr);
@@ -535,28 +535,30 @@ Ndb::handleReceivedSignal(NdbApiSignal*
* an NdbOperation.*/
assert(tOp->checkMagicNumber()==0);
tCon = tOp->theNdbCon;
- } else if(queryReceiver->checkMagicNumber()) {
- tCon = queryReceiver->getNdbTransaction();
+ } else if(queryOpImpl->checkMagicNumber()) {
+ tCon = queryOpImpl->getQuery().getNdbTransaction();
} else{
goto InvalidSignal;
}
if (tCon != NULL) {
- if (tCon->theSendStatus == NdbTransaction::sendTC_OP) {
- if(isNdbOperation){
- tReturnCode = tOp->receiveTCKEYREF(aSignal);
- if (tReturnCode != -1) {
- completedTransaction(tCon);
- return;
- }//if
- } else {
- if(queryReceiver->execTCKEYREF(aSignal) &&
- tCon->OpCompleteFailure(queryReceiver->getNdbOperation()) != -1){
- completedTransaction(tCon);
- return;
- }//if
+ if(isNdbOperation){
+ if (tCon->theSendStatus != NdbTransaction::sendTC_OP) {
+ goto InvalidSignal;
+ }
+ tReturnCode = tOp->receiveTCKEYREF(aSignal);
+ if (tReturnCode != -1) {
+ completedTransaction(tCon);
+ return;
}//if
- break;
+ } else {
+ if(queryOpImpl->execTCKEYREF(aSignal) &&
+ tCon->OpCompleteFailure(queryOpImpl->getQuery()
+ .getNdbOperation()) != -1){
+ completedTransaction(tCon);
+ return;
+ }//if
}//if
+ break;
}//if (tCon != NULL)
goto InvalidSignal;
return;
=== modified file 'storage/ndb/src/ndbapi/TransporterFacade.cpp'
--- a/storage/ndb/src/ndbapi/TransporterFacade.cpp 2009-05-28 09:12:44 +0000
+++ b/storage/ndb/src/ndbapi/TransporterFacade.cpp 2009-08-07 09:33:27 +0000
@@ -1960,8 +1960,11 @@ void PollGuard::wait_for_input(int wait_
}
}
+bool stopHere = false;
+
void PollGuard::unlock_and_signal()
{
+ // assert(!stopHere);
NdbWaiter *t_signal_cond_waiter= 0;
if (!m_locked)
return;
=== modified file 'storage/ndb/src/ndbapi/ndberror.c'
--- a/storage/ndb/src/ndbapi/ndberror.c 2009-07-24 08:55:33 +0000
+++ b/storage/ndb/src/ndbapi/ndberror.c 2009-08-07 09:33:27 +0000
@@ -743,6 +743,8 @@ ErrorBundle ErrorCodes[] = {
"Query definition too large." },
{ QRY_DUPLICATE_COLUMN_IN_PROJ, DMEC, AE,
"Duplicate column in result projection for NdbQueryOperation."},
+ { QRY_RESULT_ROW_ALREADY_DEFINED, DMEC, AE,
+ "Result row already defined for NdbQueryOperation."},
{ NO_CONTACT_WITH_PROCESS, DMEC, AE,
=== modified file 'storage/ndb/test/tools/test_spj.cpp'
--- a/storage/ndb/test/tools/test_spj.cpp 2009-08-03 07:58:08 +0000
+++ b/storage/ndb/test/tools/test_spj.cpp 2009-08-07 09:33:27 +0000
@@ -43,7 +43,7 @@ paramSpec: 00050001 00000001 00010000 00
#include <NdbQueryOperation.hpp>
#include <NdbQueryBuilder.hpp>
// 'impl' classes is needed for prototype only.
-//#include <NdbQueryOperationImpl.hpp>
+#include <NdbQueryOperationImpl.hpp>
//#include "NdbQueryBuilderImpl.hpp"
@@ -567,36 +567,70 @@ int testSerialize(int argc, char** argv)
if(scan){
const NdbRecord* resultRec = tab->getDefaultRecord();
assert(resultRec!=NULL);
- /*const NdbQueryScanOperationDef* scanOpDef = */ qb->scanTable(tab);
+ 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);
- Uint32 results[10][6];
- char* resultPtr = NULL;
- NdbQueryOperation* const op = query->getQueryOperation(0U);
- op->setResultRowRef(resultRec, resultPtr);
- myTransaction->execute(NoCommit);
+ //Uint32 results[10][6];
+ //char* resultPtr = NULL;
+ const Uint32* scanResultPtr;
+ //const unsigned char* mask = NULL;
+ NdbQueryOperation* const scanOp = query->getQueryOperation(0U);
+ scanOp->setResultRowRef(resultRec,
+ reinterpret_cast<const char*&>(scanResultPtr),
+ NULL);
+ const Uint32* 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().isComplete() &&
+ lookupOp->getImpl().isComplete())){
+ sleep(1);
+ }
bool done = false;
int rowNo = 0;
while(!done){
- resultPtr = reinterpret_cast<char*>(results[rowNo]);
- int retVal = query->nextResult();
+ // scanResultPtr = reinterpret_cast<char*>(results[rowNo]);
+ const int retVal = query->nextResult();
switch(retVal){
case 0:
break;
case 1:
done = true;
break;
+ case 2:
+ ndbout << "No more results in buffer";
+ done = true;
+ break;
default:
assert(false);
};
- for(int i = 0; i<6; i++){
- ndbout << results[rowNo][i] << " ";
+ if(!done){
+ ndbout << "Scan row: " << rowNo << endl;
+ for(int i = 0; i<6; i++){
+ ndbout << scanResultPtr[i] << " ";
+ }
+ ndbout << endl;
+ ndbout << "Loopkup row: " << rowNo << endl;
+ for(int i = 0; i<6; i++){
+ ndbout << lookupResultPtr[i] << " ";
+ }
+ ndbout << endl;
+ rowNo++;
}
- ndbout << endl;
- rowNo++;
}
}else{
/* Dummy for now at least. Key is really set with ndbOperation->equal().*/
Attachment: [text/bzr-bundle] bzr/jan.wedvik@sun.com-20090807093327-ugnnin00eqbzzd06.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-telco-7.0-spj branch (jan.wedvik:2940) | Jan Wedvik | 7 Aug |