dtl
Category: iterators | Component type: type |
DBView<DataObj, ParamObj>::select_iterator is an Input Iterator that performs the reading of objects of type DataObj from a particular DBView (and thus the database). The select_iterator generates the following SQL statement to read records from the database: "SELECT " + "<field1_fromBCA>, <field2_fromBCA>, ... " + "FROM " + "<tablename1_from_view>, <tablename2_from_view>, ... " + posfix_clause_from_view. (But see BuildSpecialQry for how to override this.) Note that all of the restrictions of an Input Iterator must be obeyed, including the restrictions on the ordering of operator* and operator++ operations.
Defined in the select_iterator.h header file.
1. Define an object to hold the rows from your query.
2. Define an association between fields in your query and fields in your object. This is what we call a 'BCA', which is short for Bind Column Addresses. In the example below, this is done via the functor "BCAExample". The job of the BCA is to equate SQL fields with object fields via the '==' operator which will then establish ODBC bindings to move data to or from a user query.
3. Create a view to select records from. This view is built from the template DBView and establishes which table(s) you want to access, what fields you want to look at (via the BCA), and an optional where clause to further limit the set of records that you are working with. The DBView template forms a semi-Container in the STL sense.1.
4. Use the DBView container
to obtain an iterator to SELECT, INSERT, UPDATE or DELETE records
from your view. These iterators may be used to either populate
STL containers or apply algorithms from the Standard Template
library.
In all the examples that follow we will assume that our database contains a table called DB_EXAMPLE of the form
SQL> desc db_example;
Name Type
------------------------------- --------
INT_VALUE INTEGER
STRING_VALUE VARCHAR
DOUBLE_VALUE FLOAT
EXAMPLE_LONG INTEGER
EXAMPLE_DATE DATE
// STEP 1 ////
// "Example" class to hold rows from our database table
class Example
{
public: // tablename.columnname:
int exampleInt; // DB_EXAMPLE.INT_VALUE
string exampleStr; // DB_EXAMPLE.STRING_VALUE
double exampleDouble; // DB_EXAMPLE.DOUBLE_VALUE
long exampleLong; // DB_EXAMPLE.EXAMPLE_LONG
TIMESTAMP_STRUCT exampleDate; // DB_EXAMPLE.EXAMPLE_DATE
Example(int exInt, const string &exStr, double exDouble, long exLong,
const TIMESTAMP_STRUCT &exDate) :
exampleInt(exInt), exampleStr(exStr), exampleDouble(exDouble), exampleLong(exLong),
exampleDate(exDate)
{ }
};
// STEP 2 ////
// Create an association between table columns and fields in our object
template<> class dtl::DefaultBCA<Example>
{
public:
void operator()(BoundIOs &cols, Example &rowbuf)
{
cols["INT_VALUE"] == rowbuf.exampleInt;
cols["STRING_VALUE"] == rowbuf.exampleStr;
cols["DOUBLE_VALUE"] == rowbuf.exampleDouble;
cols["EXAMPLE_LONG"] == rowbuf.exampleLong;
cols["EXAMPLE_DATE"] == rowbuf.exampleDate;
}
}
// STEP 3 & 4
// Read the contents of the DB_EXAMPLE table and return a vector of the
// resulting rows
vector<Example> ReadData() {
// Read the data
vector<Example> results;
DBView<Example> view("DB_EXAMPLE");
DBView<Example>::select_iterator read_it = view.begin();
for ( ; read_it != view.end(); read_it++)
{
results.push_back(*read_it);
}
return results;
}
1 See http://www.sgi.com/tech/stl/Container.html for the definition of an STL container, we
call DBView a semi container because it supports all
standard container methods except size(), max_size() and
empty(). We explain why these were left out by design in the
documentation for the DBView template.
Parameter | Description | Default |
---|---|---|
DataObj | The type of object that will be written to the DBView. This object will be bound through use of the BCA to the appropriate columns in the database. The set of value types of an DBView::select_iterator consists of a single type, DataObj. | |
ParamObj | The type of object that will be used to specify the postfix parameters to the DBView. | DefaultParamObj<DataObj> |
DataObj and ParamObj must each fulfill the following requirements:.
DB_iterator<DataObj, ParamObj>, iterator<input_iterator_tag, DataObj>
Member | Where defined | Description |
---|---|---|
DBView::select_iterator() | select_iterator | Default constructor. |
DBView::select_iterator(DBView<DataObj, ParamObj> &view) | select_iterator | See below. |
DBView::select_iterator(const DBView::select_iterator&) | Input Iterator | The copy constructor. See Note [2]. |
DBView::select_iterator& operator=(const DBView select_iterator&) | Input Iterator | The assignment operator See Note [5]. |
const DataObj &operator*() | Input Iterator | Dereferencing operator. Returns the DataObj pointed to in the DBView. This operator forbids assigning to the iterator's DataObj. |
CountedPtr<DataObj> operator->() | Input Iterator, DB_iterator | Dereferencing operator. Returns a pointer to the DataObj read from the DBView. |
DBView::select_iterator& operator++() | Input Iterator | Preincrement. Reads a DataObj from the DBView. See Note [1]. |
void operator++(int) | Input Iterator | Postincrement Reads a DataObj from the DBView. See Note [1]. |
friend bool operator==(const DBView::select_iterator &i1, const DBView::select_iterator &i2) | Input Iterator | Returns whether the two iterators are equal, that is, do they refer to the same DataObj? See Note [3]. |
friend bool operator!=(const DBView::select_iterator &i1, const DBView::select_iterator &i2) | Input Iterator | Returns whether the two iterators are not equal. Equivalent to !(i1 == i2). |
These members are not defined in the Input Iterator requirements or in DB_iterator<DataObj, ParamObj>, but are specific to DBView::select_iterator.
Function | Description |
---|---|
DBView::select_iterator(DBView<DataObj, ParamObj> &view) | Creates an select_iterator which refers to view. See Note [2]. |
void swap(DBView::select_iterator &other) | Swap *this with other. |
[1] This is the operation that actually reads the DataObj from the database via the DBView. Each DBView::select_iterator internally owns a DBStmt object which is allocated and prepared when the underlying ODBC statement handle is first needed and not before. The handle is not opened until absolutely needed in order to make copying and assigning these iterators an inexpensive operation. The DBStmt is executed on each call to operator++(), whether the prefix or postfix version.
[2] There is also a variant of this constructor which takes a second argument specifying a dummy whether the iterator is at the beginning or end of the DBView. It is used internally and should never be called by the end user.
[3] According to the C++ standard, Table 72, Section 24.1.1, page 511, certain invariants must be maintained for an Input Iterator. The select_iterator implementation both adheres to the following invariants as well as taking advantage of them (assume x and y are both select_iterators):
We use a reference counted pointer to the data and copy this pointer on assignment of the iterator to obtain the Identity invariant. However, this does not work when we copy DBView::begin() because a new recordset may be opened. In this case, we may not have *x == *y although *x and *y are equivalent in the conceptual sense as the first element of a recordset.
[4] This function is a bit peculiar for select_iterators. For the notion of a DBView's begin() and end() iterators, begin() must point to the first DataObj in the view and end() to one past the last DataObj in the view. To provide this conceptual behavior, the dereferencing operators must be able to grab the first record from the database if the iterator hasn't done so already. So the ReadData() function in the above example code will say its reading elements 0, 2, 3, 4, etc., rather than the 1, 2, 3, 4, etc., you would expect. This behavior occurs as the following happens:
[5] It is more efficient to reset your iterator to DBView::begin() if you are iterating over a view several times. When you perform the assigment select_iterator = view.begin(), the code will automatically reset the underlying recordset for you. This can represent a significant performance gain because then the database cursor does not have to be reparsed & reconstructed every time we wish to revisit the view (possibly with different selection parameters).
DB_iterator,
Output
Iterator, Input
Iterator.
Copyright © 2002, Michael Gradman and Corwin Joy.
Permission to use, copy, modify, distribute and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appears in all copies and that both that copyright notice and this permission notice appear in supporting documentation. Corwin Joy and Michael Gradman make no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty.