Using RWDBMultiRow for Ad Hoc Queries
In Output Binding and Fetching Using RWDBTBuffer, we created our own RWDBTBuffers when buffers were needed to hold query results. We could do this since we knew the format of our results in advance. If the format of results is not known, however, RWDBMultiRow can help create RWDBTBuffers for results. Let’s see how this is done.
In the example in Output Binding and Fetching Using RWDBTBuffer, we used RWDBMultiRow when we made output bindings for our results:
 
...
anOSql[0] >> idBuffer; // 7
...
The expression anOSql[0] returns an RWDBMultiRow reference, and the RWDBMultiRow operator>> appends an RWDBTBuffer to itself. RWDBOSql internally stores an RWDBMultiRow for each result set, and operator[] returns a reference to the RWDBMultiRow for the specified result set. In some cases, the number or type of columns in the result set is unknown until runtime. As we will see below, we can use RWDBMultiRow to automatically create RWDBTBuffers for us in these cases.
Class RWDBOSql provides a method, schema(), which returns an RWDBSchema representing the schema of the current result set. Each column in the returned RWDBSchema details information about the corresponding results column, including its name, datatype, and other information. RWDBMultiRow provides a constructor that takes an RWDBSchema, and creates appropriate RWDBTBuffers. Here’s an example of how we could use RWDBMultiRow to automatically create output bindings:
 
RWCString aQuery = getUserSpecifiedQuery(); //1
RWDBOSql anOSql(aQuery, RWDBOSql::Query); //2
anOSql.execute(aConn); //3
RWDBMultiRow outputBindings(anOSql.schema(), 1); //4
anOSql[0] = outputBindings; //5
 
while(anOSql.fetch(), anOSql.rowsFetched() > 0) { //6
processResults(outputBindings); //7
}
 
On //1 and //2, an RWDBOSql is created from a user-specified query, and on //3, the query is executed. Note that the output bindings are not yet specified at this time. As we explained in the example in Output Binding and Fetching Using RWDBTBuffer, output bindings may be specified before or after execute() is invoked, as long as they are specified before fetch() is invoked.
On //4, we call anOSql.schema(), which returns an RWDBSchema representing the schema of the result set. We use this RWDBSchema to construct a new RWDBMultiRow, which immediately uses this RWDBSchema to construct an RWDBTBuffer for each column. The RWDBMultiRow instantiates the RWDBTBuffer templates on the types corresponding to each column’s type, and appends the new RWDBTBuffers to itself. The 1 corresponds to the number of entries each RWDBTBuffer will have; each RWDBTBuffer will have 1 entry.
On //5, we use the new RWDBMultiRow as the output bindings for the 0th result set of our RWDBOSql. Like many classes of the standard interface of the DB Interface Module, RWDBMultiRow is designed around the Interface/Implementation paradigm, and the state of each RWDBMultiRow is held in a hidden, reference-counted implementation class. Using the assignment operator causes the RWDBOSql’s internal RWDBMultiRow for the 0th result set to refer to the implementation of the RWDBMultiRow we just constructed. The RWDBOSql now uses our newly created RWDBTBuffers, but no performance is lost by creating a copy.
Although creating this RWDBMultiRow from an RWDBSchema is a useful technique, please note that it requires extra steps while trying to access the data fetched. These extra steps are described in the next section Obtaining Data from RWDBMultiRow. All these can impose quite a performance penalty, depending on how frequently they are used.
NOTE: This technique may impede performance.
For this reason, we recommend that you use these features only when it is impossible to know the results of a query and RWDBTBuffers cannot be created based on the RWDBSchema returned by the RWDBOSql::schema()_ call. In other cases, it is preferable to directly instantiate RWDBTBuffers of the appropriate type and directly bind them to your RWDBOSql.
Lines //6 and //7 perform the standard results-processing loop that we use in Output Binding and Fetching Using RWDBTBuffer. The processResults() function processes the results fetched into the given RWDBMultiRow and its RWDBTBuffers.