335 lines
10 KiB
C++

/*
Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef NdbReceiver_H
#define NdbReceiver_H
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL // Not part of public interface
#include <ndb_types.h>
class Ndb;
class NdbImpl;
class NdbTransaction;
class NdbRecord;
class NdbRecAttr;
class NdbQueryOperationImpl;
class NdbReceiverBuffer;
class NdbReceiver
{
friend class Ndb;
friend class NdbImpl;
friend class NdbOperation;
friend class NdbQueryImpl;
friend class NdbQueryOperationImpl;
friend class NdbResultStream;
friend class NdbScanOperation;
friend class NdbIndexOperation;
friend class NdbIndexScanOperation;
friend class NdbTransaction;
friend class NdbRootFragment;
friend int compare_ndbrecord(const NdbReceiver *r1,
const NdbReceiver *r2,
const NdbRecord *key_record,
const NdbRecord *result_record,
bool descending,
bool read_range_no);
friend int spjTest(int argc, char** argv);
public:
enum ReceiverType { NDB_UNINITIALIZED,
NDB_OPERATION = 1,
NDB_SCANRECEIVER = 2,
NDB_INDEX_OPERATION = 3,
NDB_QUERY_OPERATION = 4
};
NdbReceiver(Ndb *aNdb);
int init(ReceiverType type, void* owner);
void release();
~NdbReceiver();
Uint32 getId() const{
return m_id;
}
ReceiverType getType() const {
return m_type;
}
inline NdbTransaction * getTransaction(ReceiverType type) const;
void* getOwner() const {
return m_owner;
}
bool checkMagicNumber() const;
static Uint32 getMagicNumber() { return (Uint32)0x11223344; }
Uint32 getMagicNumberFromObject() const;
inline void next(NdbReceiver* next_arg) { m_next = next_arg;}
inline NdbReceiver* next() { return m_next; }
void setErrorCode(int);
/**
* Construct a receive buffer for a batched result set.
* 'buffer' has to be allocated with size as calculated by
* result_bufsize, and pointer should be Uint32 aligned.
*/
static
NdbReceiverBuffer* initReceiveBuffer(
Uint32 *buffer,
Uint32 bufSize, // Size in Uint32 words
Uint32 batchRows);
/**
* Prepare for receiving of rows into specified buffer.
* This buffer is later navigated, and retrieved from,
* by either getNextRow() or setCurrentRow(). The row is
* then 'unpacked' into 'row_buffer' set by do_setup_ndbrecord().
*/
void prepareReceive(NdbReceiverBuffer *buf);
private:
Uint32 theMagicNumber;
Ndb* const m_ndb;
Uint32 m_id;
Uint32 m_tcPtrI;
ReceiverType m_type;
void* m_owner;
NdbReceiver* m_next;
/**
* At setup
*/
class NdbRecAttr * getValue(const class NdbColumnImpl*, char * user_dst_ptr);
void getValues(const NdbRecord*, char*);
void prepareSend();
static
void calculate_batch_size(const NdbImpl&,
Uint32 parallelism,
Uint32& batch_size,
Uint32& batch_byte_size);
void calculate_batch_size(Uint32 parallelism,
Uint32& batch_size,
Uint32& batch_byte_size) const;
/**
* Calculate size of result buffer which has to be
* allocated for a buffered result set, and later given to
* initReceiveBuffer() as 'buffer' argument.
*/
static
Uint32 result_bufsize(Uint32 batch_rows,
Uint32 batch_bytes,
Uint32 fragments,
const NdbRecord *result_record,
const Uint32* read_mask,
const NdbRecAttr *first_rec_attr,
Uint32 key_size,
bool read_range_no);
/*
Set up buffers for receiving TRANSID_AI and KEYINFO20 signals
during a scan using NdbRecord.
*/
void do_setup_ndbrecord(const NdbRecord *ndb_record,
char *row_buffer,
bool read_range_no, bool read_key_info);
/**
* Calculate size required for an 'unpacked' result row
* where the current result row is stored. A buffer of this size is used
* as 'row_buffer' argument to do_setup_ndbrecord().
*/
static
Uint32 ndbrecord_rowsize(const NdbRecord *ndb_record,
bool read_range_no);
int execKEYINFO20(Uint32 info, const Uint32* ptr, Uint32 len);
int execTRANSID_AI(const Uint32* ptr, Uint32 len);
int execTCOPCONF(Uint32 len);
int execSCANOPCONF(Uint32 tcPtrI, Uint32 len, Uint32 rows);
/* Assist functions to execTRANSID_AI */
const Uint32 * handle_extra_get_values(Uint32 & save_pos,
Uint32 * aLength,
const Uint32 *aDataPtr,
Uint32 attrSize,
bool isScan,
Uint32 attrId,
Uint32 origLength,
bool & ndbrecord_part_done);
const Uint32 * handle_attached_rec_attrs(Uint32 attrId,
const Uint32 *aDataPtr,
Uint32 origLength,
Uint32 attrSize,
Uint32 * aLength);
/* Convert from packed transporter to NdbRecord / RecAttr format. */
int unpackRow(const Uint32* ptr, Uint32 len, char* row);
/* NdbRecord describing row layout expected by API */
const NdbRecord *m_ndb_record;
/* The (single) current row in 'unpacked' NdbRecord format */
char *m_row_buffer;
/* Block of memory used to buffer all rows in a batch during scan. */
NdbReceiverBuffer *m_recv_buffer;
/**
* m_read_range_no & m_read_key_info is true if we are reading
* range / keyinfo as part of scans.
*/
bool m_read_range_no;
bool m_read_key_info;
/**
* Holds the list of RecAttr defined by getValue()
* which to retrieve data into when a row is unpacked.
* These RecAttr's are owner by this NdbReceiver and
* terminated by ::release()
*/
class NdbRecAttr* m_firstRecAttr;
class NdbRecAttr* m_lastRecAttr; // A helper for getValue()
/* Savepoint for unprocessed RecAttr data from current row. */
const Uint32* m_rec_attr_data;
Uint32 m_rec_attr_len;
/*
When an NdbReceiver is sitting in the NdbScanOperation::m_sent_receivers
array, waiting to receive TRANSID_AI data from the kernel, its index into
m_sent_receivers is stored in m_list_index, so that we can remove it when
done without having to search for it.
*/
Uint32 m_list_index;
/*
m_current_row holds the next row / key to be delivered to
the application.
*/
Uint32 m_current_row;
/*
m_expected_result_length: Total number of 32-bit words of TRANSID_AI and
KEYINFO20 data to receive. This is set to zero until SCAN_TABCONF has
been received.
*/
Uint32 m_expected_result_length;
Uint32 m_received_result_length;
/**
* Unpack a packed stream of field values, whose presence and nullness
* is indicated by a leading bitmap into a list of NdbRecAttr objects
* Return the number of words read from the input stream.
*/
static
Uint32 unpackRecAttr(NdbRecAttr**, Uint32 bmlen,
const Uint32* aDataPtr, Uint32 aLength);
/**
* Unpack a stream of field values, whose presence and nullness
* is indicated by a leading bitmap, into an NdbRecord row.
* Return the number of words consumed.
*/
static
Uint32 unpackNdbRecord(const NdbRecord *record, Uint32 bmlen,
const Uint32* aDataPtr,
char* row);
/**
* Handle a stream of field values, both 'READ_PACKED' and plain
* unpacked fields, into a list of NdbRecAttr objects.
* Return 0 on success, or -1 on error
*/
static
int handle_rec_attrs(NdbRecAttr* rec_attr_list,
const Uint32* aDataPtr,
Uint32 aLength);
/**
* Unpack data for the specified 'row' previously stored into
* the 'buffer'. Handles both the row in NdbRecord format, and
* the key recieved as KEYINFO, if present.
*/
const char *unpackBuffer(const NdbReceiverBuffer *buffer, Uint32 row);
/**
* Result set is navigated either sequentialy or randomly to a
* specific row. The NdbRecord contents is then unpacked into
* 'm_row_buffer' and returned. KeyInfo, Range no and RecAttr
* values may be retrieved by specific calls below.
*/
const char *getRow(const NdbReceiverBuffer* buffer, Uint32 row);
const char *getNextRow();
/* Fetch the NdbRecord part of current row */
const char *getCurrentRow() const { return m_row_buffer; }
/* get_range_no() returns the range_no for current row. */
int get_range_no() const;
/* Fetch keyinfo from KEYINFO20 signal for current row. */
int get_keyinfo20(Uint32 & scaninfo, Uint32 & length,
const char * & data_ptr) const;
/** Fetch RecAttr values for current row. */
int get_AttrValues(NdbRecAttr* rec_attr_list) const;
};
#ifdef NDB_NO_DROPPED_SIGNAL
#include <stdlib.h>
#endif
inline
bool
NdbReceiver::checkMagicNumber() const {
bool retVal = (theMagicNumber == getMagicNumber());
#ifdef NDB_NO_DROPPED_SIGNAL
if(!retVal){
abort();
}
#endif
return retVal;
}
inline
Uint32
NdbReceiver::getMagicNumberFromObject() const
{
return theMagicNumber;
}
inline
int
NdbReceiver::execTCOPCONF(Uint32 len){
const Uint32 tmp = m_received_result_length;
m_expected_result_length = len;
#ifdef assert
assert(!(tmp && !len));
#endif
return ((bool)len ^ (bool)tmp ? 0 : 1);
}
#endif // DOXYGEN_SHOULD_SKIP_INTERNAL
#endif