SourcePro® API Reference Guide

 
List of all members | Public Member Functions
RWDBDataCallback Class Referenceabstract

Base class for user-defined callbacks. More...

#include <rw/db/datacb.h>

Inheritance diagram for RWDBDataCallback:
RWDBBinaryCallback RWDBCharCallback RWDBUChar16Callback

Public Member Functions

size_t entries () const
 
virtual size_t getLength (size_t rownum) const
 

Detailed Description

RWDBDataCallback is an abstract base class for the encapsulation of user-defined data callbacks. Derive from one of the type-specific classes RWDBCharCallback, RWDBUChar16Callback, or RWDBBinaryCallback to implement new callback instances.

Synopsis
#include <rw/db/datacb.h>
Example
In this example, we define a data callback to insert and fetch data. The program will create a test table with one column of a LOB character type. It will then execute an INSERT statement to insert 10 rows of data and then execute a SELECT statement to read the rows that were inserted.
#include <rw/db/db.h>
#include <rw/db/tbuffer.h>
#include <rw/db/datacb.h>
using namespace std;
const size_t LENGTH = 20000;
const size_t PIECES = 3;
class MyCallback : public RWDBCharCallback
{
public:
MyCallback(size_t rowsetSize) : RWDBCharCallback(rowsetSize), offset(0)
{ }
virtual ~MyCallback() { }
bool onFetch(size_t rownum, const char* theData, size_t length,
RWDBNullIndicator ni, bool& lastPiece)
{
cout << endl << "Row in rowset is: " << rownum << endl;
cout << "Row in result set is: " << (rownum + offset) << endl;
if (ni) {
cout << "Read a null" << endl;
}
else if (lastPiece) {
cout << "Read a piece of data of length " << length << endl;
cout << "Received the last piece of data for row " << rownum << endl;
}
else {
cout << "Read a piece of data of length " << length << endl;
}
return true;
}
bool onSend(size_t rownum, char* theData, size_t& length,
RWDBNullIndicator& ni, bool& lastPiece)
{
static size_t piecesSent = 0;
static RWCString tmp('a', LENGTH);
// populate the array, theData, with the data we're inserting
length = LENGTH;
memcpy((void*)theData, tmp.data(), LENGTH);
// keep track of how many pieces for this row have been sent
++piecesSent;
// if this is the 3rd piece it will be the last one for this value
if (piecesSent == PIECES) {
lastPiece = true;
piecesSent = 0;
}
return true;
}
// We may or may not need to return the length of the data we're sending.
// This depends on the Access Module in use.
size_t getLength(size_t rownum) const
{
return LENGTH * PIECES;
}
// We keep a row offset when fetching data as some vendors will only
// return 1 row on each call to RWDBOSql::fetch(). We use this to count
// the total number of rows that are fetched from the SELECT query.
void addToRowOffset(size_t rowsFetched)
{
offset += rowsFetched;
}
// Set the row offset value to newValue.
void setOffset(size_t newValue)
{
offset = newValue;
}
private:
size_t offset;
};
int main()
{
RWDBDatabase db = RWDBManager::database("msq8015d.dll", "SQL SERVER DB",
"username", "password", "DB");
RWDBConnection cn = aDatabase.connection();
RWCString tableName("myTestTable");
RWDBTable tbl = db.table(tableName);
// Create the table if needed. If it already exists delete the rows.
if (!tbl.exists()) {
sch.appendColumn("col1", RWDBValue::String, INT_MAX);
db.createTable("myTestTable", sch);
}
else {
RWDBDeleter del = tbl.deleter();
del.execute(cn);
}
// Declare a data callback. Set the entries to 5. This will be
// the maximum number of rows that can be fetched on each call to
// RWDBOSql::fetch() or the maximum number of rows that will be sent
// on the call to RWDBOSql::execute().
MyCallback cbin(5);
RWDBOSql sql("insert into " + tableName + " values(?)");
sql << cbin;
// Execute the insert statement.
// MyCallback::onSend(..) will be called as many times as needed
// to insert 5 rows of data. Note that the method MyCallback::getLength()
// may or may not be needed. If needed, it will be called once for each
// row being sent just before onSend() is called for the row.
sql.execute(cn);
// Check if the insert succeeded or not.
if (sql.isValid()) {
cout << "inserted 5 rows" << endl;
}
else {
cout << "inserting rows failed" << endl;
}
// Insert another 5 rows.
sql.execute(cn);
if (sql.isValid()) {
cout << "inserted another 5 rows" << endl;
}
else {
cout << "inserting another 5 rows failed" << endl;
}
// Declare a callback to fetch data. It can accommodate a maximum
// of 3 rows of data on each call to RWDBOSql::fetch().
MyCallback cbout(3);
sql.statement("select * from " + tableName);
// Execute the statement.
sql.execute(cn);
// Check if execution succeeded or failed.
if (sql.isValid()) {
// Bind the callback buffer to the 0th result set.
sql[0] >> cbout;
// Fetch the rows. Note that each call to sql.fetch() will fetch
// a maximum of 3 rows - the size specified in the constructor
// of RWDBCharCallback.
while (sql.fetch(), sql.rowsFetched() > 0) {
// Use this so the callback can keep track of the total
// number of rows fetched from executing the SELECT statement.
cbout.addToRowOffset(sql.rowsFetched());
}
}
return 0;
}

Member Function Documentation

size_t RWDBDataCallback::entries ( ) const
inline

Returns the number of entries. The number of entries refers to the maximum size of the rowset that can be used with this callback. It is equivalent to the entries in RWDBTBuffer. Please see the class reference for RWDBOSql and the section "Using the Open SQL Classes" of the DB Interface Module User's Guide for more information.

virtual size_t RWDBDataCallback::getLength ( size_t  rownum) const
inlinevirtual

Returns the length of the data that will be sent for the row rownum. Whether this value is needed depends on the database vendor. Please see the Access Module User's Guide for your database to make this determination. This method must be overridden in the derived class if the length of the data is needed.

Copyright © 2023 Rogue Wave Software, Inc., a Perforce company. All Rights Reserved.