Fetching Data with a Custom Callback Class
To use a custom callback class with Open SQL to fetch data, the onFetch() method must be implemented. An instance of the class is associated with an RWDBOSql so the results produced by executing a SQL statement are passed to the callback class. Here is an example fetching data with a custom callback class based on the image data example in Fetching Data.
 
class MyCallback : public RWDBBinaryCallback
{
public:
MyCallback(size_t rowsetSize) : RWDBBinaryCallback(rowsetSize), ourRowCount(0)
{ }
virtual ~MyCallback() { }
 
bool onFetch(size_t rownum, const void* theData, size_t length,
RWDBNullIndicator ni, bool& lastPiece)
{
if (!ni) {
// assume that the data is written to some pre-defined location
passToSink(ourRowCount, theData, length);
}
else {
passNullToSink(ourRowCount);
}
 
if (lastPiece) {
++ourRowCount;
}
 
return true;
}
 
. . .
private:
size_t ourRowCount;
};
 
RWDBDatabase aDB = RWDBManager::database(...);
RWDBConnection aConn = aDb.connection();
RWDBOSql anOSql("SELECT ID, IMAGE FROM INVENTORY", RWDBOSql::Query);
anOSql.execute(aConn);
if (anOSql.isValid() && anOSql.hasResult()) {
unsigned long idArray[100]; // 1
RWDBTBuffer<unsigned long> idBuffer(idArray, 100); // 2
MyCallback myCB(100); // 3
anOSql[0] >> idBuffer >> myCB; // 4
 
while (anOSql.fetch(), anOSql.rowsFetched() > 0) { // 5
printInventoryIDs(idArray, anOSql.rowsFetched());
}
}
//1 Creates an array of 100 unsigned long values on the stack.
//2 Encapsulates the array in an RWDBTBuffer, idBuffer, so the array can be used as an output binding.
//3 Declares an instance of a custom callback class that is able to work with multiple rows. This implies that the database supports array binding, which allows us to fetch multiple rows in a single call to onFetch(). Note, however, that if this were declared for a database that did not support array binding, the callback class would still work; the database would just only ever populate one row of the array.
//4 Binds idBuffer to the first column in the result set, the ID column specified in the SELECT statement, and binds myCB to the second column, IMAGE.
//5 Begins the results processing loop, which calls fetch() to fetch data, and exits the loop if rowsFetched() returns 0.
In the calls to fetch(), the custom callback class onFetch() method is called repeatedly until all the data is fetched for the rows returned. On each call to fetch(), RWDBOSql fetches as many rows as possible from the result set. In this case, the output binding holds 100 entries and the custom callback class was constructed with an entries value of 100, so at most 100 rows are fetched. If fewer rows are available in the result set, all the rows are fetched.
After each call to fetch(), the function rowsFetched() returns the number of rows fetched, which indicates the part of the array that contained the fetched data and how many rows of data were passed to the callback's onFetch() method. When all the result data is exhausted, calling fetch() returns no rows and rowsFetched() returns 0, exiting the loop.