Teach Yourself Database Programming
with Visual C++ 6 in 21 days


Day 20
      Properties, Transactions, and Indexes



Today's lesson covers three important topics in OLE DB application development: properties, transactions, and the Index object. You have already learned about OLE DB objects and have used their methods, but you haven't yet discovered how to change the state of an object. Today you will learn how to use properties to control the state of an object, or in other words, how to set and retrieve property values of OLE DB objects by using special interfaces. The other major topics for today are the Transaction object and the Index object.

Today you will

Properties and Groups

Properties specify the attributes of an OLE DB object and can determine how the object behaves. Some properties can only be read, whereas others can be read and written. Properties are identified by globally unique identifier (GUID) constants and grouped according to the object on which they function. The following objects have special properties: Columns, DataSource, DataSource initialization objects, Index, Rowset, Session, and Table. Today's explanation of properties begins by discussing how to retrieve a property value.

Getting Properties

Most OLE DB objects use the GetProperties method to retrieve property values. Table 20.1 summarizes the methods used by each OLE DB object to access its properties. Because most objects use the GetProperties method, this section focuses on that mechanism for retrieving property values.

Table 20.1  The Methods Used by OLE DB Objects to Retrieve Property Values
OLE DB Object
Interface
Method
ColumnsIcolumnsRowset GetColumnsRowset
DataSourceIDBProperties GetProperties
IndexIRowsetIndex GetIndexInfo
RowsetIRowsetInfo
IcommandInfo
IcommandProperties
GetProperties
GetProperties
GetProperties
SessionIsessionProperties GetProperties
TableITableDefinition CreateTable

The GetProperties method is defined as follows:

GetProperties(ULONG lNumPropIDs, DBPROPIDSET rPropIDs[],
              ULONG lNumPropSets, DBPROPSET **prPropSets);

The lNumPropIDs parameter specifies the number of elements in the rPropIDs array. The rPropIDs array contains a collection of DBPROPIDSET structures that specify the collection of properties for which you want to see values. The DBPROPIDSET structure is defined as follows:

typedef struct tagDBPROPIDSET {
     DBPROPID *rgPropertyIDs;
     ULONG    cPropertyIDs;
     GUID     guidPropertySet;
} DBPROPIDSET;

The rgPropertyIDs field defines an array of Property IDs. That is, the DBPROPIDSET holds a collection of property IDs, and the GetProperties method actually takes a collection of DBPROPIDSET structures, which in themselves contain a collection of property IDs. You will typically define a single DBPROPIDSET structure, which contains a collection of the property IDs you want to retrieve. The cPropertyIDs field defines the number of elements in the rgPropertyIDs array. The guidPropertySet field holds a GUID that defines the property group to which the properties in the rgPropertyIDs array belong. Table 20.2 defines the group GUID constants and the OLE DB object they define.

Table 20.2  The OLE DB Property Groups
OLE DB Object
Group GUID Constant
ColumnDBPROPSET_COLUMN
DataSourceDBPROPSET_DATASOURCE
DataSource (information)DBPROPSET_DATASOURCEINFO
DataSource (initialization)DBPROPSET_DBINIT
IndexDBPROPSET_INDEX
RowsetDBPROPSET_ROWSET
SessionDBPROPSET_SESSION
Table
DBPROPSET_TABLE

To retrieve a property value, you must create the DBPROPIDSET structure that contains the properties you want to retrieve. On return, the prPropSet parameter contains a pointer to an array of DBPROPSET structures, and each array element contains a collection of property values. The DBPROPSET structure is defined as the following:

typedef struct tagDBPROPSET {
     DBPROP *rgProperties;
     ULONG   cProperties;
     GUID    guidPropertySet;
} DBPROPSET;
NOTE
The memory used by the prPropSet parameter is allocated by the call to the GetProperties method. The Free method of the Imalloc interface should be used to deallocate this memory when it is no longer required. You can also use the CoTaskMemFree API call if you don't have a pointer to the IMalloc interface available. It saves several lines of code, and it's functionally equivalent.

The rgProperties field defines an array of DBPROP structures. The DBPROP structures hold the actual property values. The cProperties field defines the number of elements in the rgProperties array. The guidProperties defines the property group to which the properties in the rgProperties array belong. The DBPROP structure, which holds the actual property values, is defined as follows:

typedef struct tagDBPROP {
     DBPROPID      dwPropertyID;
     DBPROPOPTIONS dwOptions;
     DBPROPSTATUS  dwStatus;
     DBID          colid;
     VARIANT       vValue;
} DBPROP;

The dwPropertyID field defines the property ID; it is defined as a simple DWORD type. The dwOptions field determines whether the property is optional or required and what to do if much of processing is required to set the value. The dwOptions field is a combination of the constants: DBPROPOPTIONS_REQUIRED if the value is required and DBPROPOPTIONS_SETIFCHEAP to determine whether it should be set if it takes much processing. The dwStatus determines the status of the property. Table 20.3 defines the possible values of the dwStatus field and their meanings. The colid field defines the column for which this property is defined. The colid is a DBID type structure, as you might recall from Day 18, "Querying a Data Source." Finally the vValue field defines the value of the property; it's defined as a standard C++ VARIANT type.

Table 20.3  The Property Status Values
Status Value
Description
DBPROPSTATUS_OKThe property's value has been successfully set.
DBPROPSTATUS_BADCOLUMNThe colid field doesn't define a valid field.
DBPROPSTATUS_BADOPTIONThe dwOptions field contained an illegal value.
DBPROPSTATUS_BADVALUEThe vValue field contained an illegal value.
DBPROPSTATUS_CONFLICTINGChanging the value of this property would result in a conflicting state; the operation was performed.
Status ValueDescription
DBPROPSTATUS_NOTALLSETTABLEWhen trying to set a property that applies to a set of columns, the operation was denied because it couldn't be set for all columns.
DBPROPSTATUS_NOTSETThe DBPROPOPTIONS_SETIFCHEAP option prevented the property from being set.
DBPROPSTATUS_NOTSETTABLEYou can't set the value of a read-only property.
DBPROPSTATUS_NOTSUPPORTEDThe data provider doesn't support the specified property.

Now that you have the background information you need in order to use the GetProperties method, you can construct the appropriate structures to retrieve a property's value and interpret the results. You need to define one structure to define the property ID you want to retrieve, and you need to define one structure to return the actual property values. (A listing and descriptions of OLE DB object property IDs appear later in this lesson.)

In the Day 18 compendium of the SQL command language, I discussed the use of the GetProperties method of the IDBProperties interface to determine whether the data provider supported the SQL command language. The property ID to check for SQL support is DPROP_SQLSUPPORT. This property is represented as a long integer, which determines the level of SQL support provided by the data provider. Listing 20.1 demonstrates how to retrieve the DBPROP_SQLSUPPORT property of the DataSource object to determine the level of SQL support provided by the data provider. Note that for brevity, the code in Listing 20.1 doesn't check the return value from GetProperties. Without testing the HRESULT, you have no way of knowing whether the properties were actually returned. In your production code, you will need to test for the return value.


Listing 20.1  Determining the Level of SQL Support Provided by a Data Provider, Using the DBSQL_SUPPORT Property

 1:    PropID =  DBPROP_SQLSUPPORT;              // SQL Support
 2:                                              // Interface
 3:    PropIDSet.rgPropertyIDs = &PropID;        // Specify the
 4:                                              // property ID
 5:    PropIDSet.cPropertyIDs = 1;               // Only one Property ID
 6:    PropIDSet.guidPropertySet = DBPROPSET_DATASOURCEINFO;
                                                 // It's a DataSource
 7:                                              // object Property
 8:
 9:    // Retrieve the Properties
10:    pIDBProperties->GetProperties(1, &PropIDSet, &lNumProps,
                                        &pPropSet);
11:
12:    // Interpret the property value
13:    if(pPropSet->rgProperties->vValue.lVal & DBPROPVAL_SQL_NONE) {
14:       cout << "SQL Commands are not supported\n";
15:    };
16:
17:    if(pPropSet->rgProperties->vValue.lVal &
             DBPROPVAL_SQL_ODBC_MINIMUM) {
18:       cout << "ODBC Minimum SQL Commands supported\n";
19:    };
20:
21:    if(pPropSet->rgProperties->vValue.lVal &
             DBPROPVAL_SQL_ODBC_CORE) {
22:       cout << "ODBC Core SQL Commands supported\n";
23:    };
24:
25:    if(pPropSet->rgProperties->vValue.lVal &
              DBPROPVAL_SQL_ODBC_EXTENDED) {
26:       cout << "ODBC Extended SQL Commands supported\n";
27:    };
28:
29:    if(pPropSet->rgProperties->vValue.lVal &
              DBPROPVAL_SQL_ANSI92_ENTRY) {
30:       cout << "ANSI 92 Entry SQL Commands supported\n";
31:    };
32:
33:    if(pPropSet->rgProperties->vValue.lVal &
              DBPROPVAL_SQL_FIPS_TRANSITIONAL) {
34:       cout << "FIPS Transitional SQL Commands supported\n";
35:    };
36:
37:    if(pPropSet->rgProperties->vValue.lVal &
              DBPROPVAL_SQL_ANSI92_INTERMEDIATE) {
38:       cout << "ANSI 92 Intermediate SQL Commands supported\n";
39:    };
40: 
41:    if(pPropSet->rgProperties->vValue.lVal &
              DBPROPVAL_SQL_ANSI92_FULL) {
42:       cout << "ANSI 92 Full SQL Commands supported\n";
43:    };
44:
45:    if(pPropSet->rgProperties->vValue.lVal &
              DBPROPVAL_SQL_ANSI89_IEF) {
46:       cout << "ANSI 89 Integrity Enhancement Facility
                 SQL Commands supported\n";
47:    };

NOTE
OLE DB also provides the GetPropertyInfo and GetCreationProperties methods to retrieve additional information about the properties that each object makes available.

Setting Properties

To establish a connection to the DataSource object by using the OLE DB ODBC provider, you used the SetProperties method (refer to Day 18) to specify the required ODBC connection parameters. The primary method that OLE DB objects use to specify property values is the SetProperties method. The SetProperties method is defined as follows:

SetProperties(ULONG cPropertySets, DBPROPSET rgPropertySets[]);

The cPropertySets parameter specifies the number of elements in the rgPropertySets array. This array contains a collection of property values. The rgPropertySets parameter is a DBPROPSET type, discussed earlier today. To set the value of a property, you need to create the rgPropertySets array and call the SetProperties method.

TIP
On return from the SetProperties method, check the status of each property to determine whether it was set properly.

Property status values are listed in Table 20.3. Table 20.4 lists the methods that each OLE DB object uses in order to specify property values.

Table 20.4  The Methods Used by OLE DB Objects to Specify Property Values
OLE DB Object
Interface
Method
ColumnsIColumnsRowset AddColumn
DataSourceIDBProperties SetProperties
IndexIRowsetIndex GetIndexInfo
RowsetIRowsetInfo GetProperties
 ICommandProperties SetProperties
SessionISessionProperties SetProperties
TableITableDefinition CreateTable

Now that you understand the structures involved in specifying a property, you can specify a property value and check the status of the property set operation. Listing 20.2 demonstrates how to use the DBPROP_INIT_TIMEOUT property. (The complete source code is on the CD-ROM.) This property is part of the DBPROPSET_DBINIT group and is used to specify the number of seconds to wait while a connection to the data source is established. Note that for brevity, the code in Listing 20.2 doesn't check the return values. In your production code, you will need to test for the return values.


Listing 20.2  How to Use the SETPROPERTIES Method to Set the DBPROP_INIT_TIMEOUT Property

 1:    // Obtain Access To The OLE DB - ODBC Provider
 2:    CoCreateInstance(CLSID_MSDASQL, NULL, CLSCTX_INPROC_SERVER,
 3:                      IID_IDBInitialize, (void **) &pIDBInitialize);
 4:
 5:    // Initialize the property values
 6:    VariantInit(&InitProperties[0].vValue);
 7:    InitProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
 8:    InitProperties[0].colid = DB_NULLID;
 9:    InitProperties[0].dwPropertyID = DBPROP_INIT_TIMEOUT;
10:    InitProperties[0].vValue.vt = VT_I4;
11:
12:    // Set the timeout value to 90 seconds
13:    InitProperties[0].vValue.lVal = 90;
14:
15:    // Specify the Property Set
16:    rgInitPropSet[0].guidPropertySet = DBPROPSET_DBINIT;
17:    rgInitPropSet[0].cProperties = 1;
18:    rgInitPropSet[0].rgProperties = InitProperties;
19:
20:    // set initialization properties
21:    pIDBInitialize->QueryInterface(IID_IDBProperties,
                                          (void **)&pIDBProperties);
22:    pIDBProperties->SetProperties(1,rgInitPropSet);
23:    // Remember to release pIDBInitialize and pIDBProperties.

A Review of OLE DB Object Properties

Table 20.5 lists all the properties that OLE DB objects support. This table lists each property ID and its variant type. An asterisk (*) after a property name signifies that it is a read-only property.

NOTE
Certain data providers might provide their own set of properties, so check the data provider documentation for more information. For example, the OLE DB ODBC data provider supports its own set of properties. These properties are part of two OLE DB ODBC provider-specific groups: DBPROPSET_PROVDERDATASOURCEINFO and DBPROPSET_PROVIDERROWSET.

Table 20.5  The Properties Supported by OLE DB Objects
Property
Description
Column Object Properties
DBPROP_COL_AUTOINCREMENTA VT_BOOL type property. If it's true, the column will automatically increment.
DBPROP_COL_DEFAULTA property of any type. It specifies the default value of a column.
DBPROP_COL_DESCRIPTIONA VT_STR type property. It specifies a column description.
DBPROP_COL_FIXEDLENGTHA VT_BOOL type property. If it's true, the column has a fixed length.
DBPROP_COL_NULLABLEA VT_BOOL type property. If it's true, the column can contain NULL values.
DBPROP_COL_PRIMARYKEYA VT_BOOL type property. If it's true, this column is part of the primary key.
DBPROP_COL_UNIQUEA VT_BOOL type property. If it's true, this column must be unique.
DataSource Object Properties
DBPROP_CURRENTCATALOGA VT_BSTR type property. It names the current data source catalog.
DataSource Object Properties (Information)
DBPROP_ACTIVESESSIONS *A VT_I4 type property. It specifies the maximum number of sessions; if 0, sessions are unlimited.
DBPROP_ASYNCTXNABORT *A VT_BOOL type property. If it's true, transactions can be aborted asynchronously.
DBPROP_ASYNCTXNCOMMIT *A VT_BOOL type. If it's true, transactions can be committed asynchronously.
DataSource Object Properties (Information)
DBPROP_BYREFACCESSORS *A VT_BOOL type property. If it's true, the data source can accept parameters passed by reference (as pointers).
DBPROP_CATALOGLOCATION *A VT_I4 type property. It returns DBPROPVAL_CL_START if the catalog name is at the beginning or DBPROPVAL_CL_END if it's at the end.
DBPROP_CATALOGTERM *A VT_BSTR type property. It specifies the name that a data source uses for a catalog.
DBPROP_CATALOGUSAGE *A VT_I4 type property. It's used to determine where catalog names are supported.
DBPROP_COLUMNDEFINITION *A VT_I4 type property. It's used to determine valid column states.
DBPROP_CONCATNULLBEHAVIORA VT_I4 type property. It determines how NULL strings are handled when added to other character strings.
DBPROP_DATASOURCENAME *A VT_BSTR type property. It specifies the name of the data source.
DBPROP_DATASOURCEREADONLY *A VT_BOOL type property. If it's true, the data source is read-only.
DBPROP_DBMSNAME *A VT_BSTR type property. It specifies the name of the data provider.
DBPROP_DBMSVER *A VT_BSTR type property. It specifies the version of the data provider.
DBPROP_DSOTHREADMODEL *A VT_I4 type property. It specifies the threading model supported by the data provider.
DBPROP_GROUPBY *A VT_I4 type property. It specifies how the GROUP BY clause functions.
DBPROP_HETEROGENEOUSTABLES *A VT_I4 type property. It specifies whether joins can be performed across providers or catalogs.
DBPROP_IDENTIFIERCASE *A VT_I4 type parameter. It specifies whether the case of identifiers is significant.
DBPROP_MAXINDEXSIZE *A VT_I4 type parameter. It specifies the maximum size of a key; if 0, there is no limit.
DataSource Object Properties (Information)
DBPROP_MAXROWSIZE *A VT_I4 type parameter. It specifies the maximum length of a row; if 0, there is no limit.
DBPROP_MAXROWSIZEINCLUDESBLOB * A VT_BOOL type parameter. If it's true, the DBPROP_MAXROWSIZE property includes BLOB fields.
DBPROP_MAXTABLESINSELECT *A VT_I4 type parameter. It specifies the maximum number of tables that can be used in a SELECT statement.
DBPROP_MULTIPLEPARAMSETS *A VT_BOOL type parameter. If it's true, the data source supports multiple parameter sets.
DBPROP_MULTIPLERESULTS *A VT_I4 type parameter. It specifies whether the data source can support multiple resultsets.
DBPROP_MULTIPLESTORAGEOBJECTS * A VT_BOOL type parameter. If it's true, the data source can open multiple objects at the same time.
DBPROP_MULTITABLEUPDATE *A VT_BOOL type parameter. If it's true, the data source can update row sets that contain multiple tables.
DBPROP_NULLCOLLATION *A VT_I4 type parameter. It specifies how NULL values are handled when sorting.
DBPROP_OLEOBJECTS *A VT_I4 type parameter. It specifies whether BLOB and OLE objects can be accessed through streaming or storage objects.
DBPROP_ORDERBYCOLUMNSINSELECT * A VT_BOOL type parameter. If it's true, the columns specified in an ORDER BY clause must be part of the SELECT statement.
DBPROP_OUTPUTPARAMETERAVAILABILITY * A VT_I4 type parameter. It specifies when output parameters can be accessed.
DBPROP_PERSISTENTIDTYPE *A VT_I4 type parameter. It specifies the type of persistent DBID supported by a data source.
DBPROP_PREPAREABORTBEHAVIOR * A VT_I4 type parameter. It specifies what happens to a prepared statement when it's aborted in a transaction.
DataSource Object Properties (Information)
DBPROP_PREPARECOMMITBEHAVIOR * A VT_I4 type parameter. It specifies what happens to a prepared statement when it's committed in a transaction.
DBPROP_PROCEDURETERM *A VT_BSTR type parameter. It specifies what the data source calls a procedure.
DBPROP_PROVIDERNAME *A VT_BSTR type parameter. It specifies the executable filename of the provider.
DBPROP_PROVIDEROLEDBVER *A VT_BSTR type parameter. It specifies the OLE DB specification version supported by the provider.
DBPROP_PROVIDERVER *A VT_BSTR type parameter. It specifies the version of the data provider.
DBPROP_QUOTEDIDENTIFIERCASE * A VT_I4 type parameter. It specifies how case is handled for quoted identifiers.
DBPROP_ROWSETCONVERSIONSONCOMMAND * A VT_BOOL type parameter. If it's true, an inquiry can be made about conversions on the row sets of a command.
DBPROP_SCHEMATERM *A VT_BSTR type parameter. It specifies the term used by the data source for a schema.
DBPROP_SCHEMAUSAGE *A VT_I4 type parameter. It specifies how schema names can be used in commands.
DBPROP_SQLSUPPORT *A VT_I4 type parameter. It specifies the level of SQL supported by the data source.
DBPROP_STRUCTUREDSTORAGE *A VT_I4 type parameter. It specifies streaming interfaces supported for row sets.
DBPROP_SUBQUERIES *A VT_I4 type parameter. It specifies whether subqueries are supported in commands.
DBPROP_SUPPORTEDTXNDDL *A VT_I4 type parameter. It specifies whether data definition commands are supported in transactions.
DBPROP_SUPPORTEDTXNISOLEVELS * A VT_I4 type parameter. It specifies the transaction isolation levels supported by the data source.
DataSource Object Properties (Information)
DBPROP_SUPPORTEDTXNISORETAIN * A VT_I4 type parameter. It specifies the retention levels supported by transaction isolation.
DBPROP_TABLETERM *A VT_BSTR type parameter. It specifies the term used by the data source for tables.
DBPROP_USERNAME *A VT_BSTR type parameter. It specifies the name of the user attached to the data source.
DataSource Object Properties (Initialization)
DBPROP_AUTH_CACHE_AUTHINFOA VT_BOOL type parameter. If it's true, the data source can store password and user information in a local cache.
DBPROP_AUTH_ENCRYPTPASSWORDA VT_BOOL type parameter. If it's true, the data source requires the password to be sent in an encrypted form.
DBPROP_AUTH_INTEGRATEDA VT_BSTR type parameter. It specifies the name of the authentication service to be used.
DBPROP_AUTH_MASK_PASSWORDA VT_BOOL type parameter. If it's true, the password must be masked before it's sent to the data source.
DBPROP_AUTH_PASSWORDA VT_BSTR type parameter. This is the password used for authentication (can be masked).
DBPROP_AUTH_PERSISTENCRYPTEDA VT_BOOL type parameter. If it's true, the data source must save authentication information.
DBPROP_AUTH_PERSIST_SENSITIVEAUTHINFO A VT_BOOL type parameter. If it's true, the data source is allowed to persist authentication information.
DBPROP_AUTH_USERIDA VT_BSTR type parameter. It specifies the username used to connect to the data source.
DBPROP_INIT_DATASOURCEA VT_BSTR type parameter. This is the name of the data source to connect to.
DBPROP_INIT_HWNDA VT_I4 type parameter. This is the window handle used if a prompt window must be displayed when accessing the data source.
DataSource Object Properties (Initialization)
DBPROP_INIT_IMPERSONATIONLEVEL A VT_I4 type parameter. It specifies the impersonation level used for remote procedure calls.
DBPROP_INIT_LCIDA VT_I4 type parameter. It specifies the location identifier.
DBPROP_INIT_LOCATIONA VT_BSTR type parameter. It specifies the location of the data source (that is, the name of the server).
DBPROP_INIT_MODEA VT_I4 type parameter. It specifies the read, write, share access level to the data source.
DBPROP_INIT_PROMPTA VT_I4 type parameter. It specifies whether a prompt should be displayed for user/data source information if it's required when connecting to a data source.
DBPROP_INIT_PROTECTION_LEVELA VT_I4 type parameter. It specifies the remote procedure call connection level used.
DBPROP_INIT_PROVIDERSTRINGA VT_BSTR type parameter. It specifies provider-specific connection parameters.
DBPROP_INIT_TIMEOUTA VT_I4 type parameter. It specifies the amount of time to wait for a connection to complete.
Index Object Properties
DBPROP_INDEX_AUTOUPDATEA VT_BOOL type parameter. If it's true, the index is automatically updated whenever a change is made.
DBPROP_INDEX_CLUSTEREDA VT_BOOL type parameter. If it's true, the index uses clustering.
DBPROP_INDEX_FILLFACTORA VT_I4 type parameter. It specifies the B+tree fill factor for the index.
DBPROP_INDEX_INITIALSIZEA VT_I4 type parameter. It specifies the initial size to allocate for the index.
DBPROP_INDEX_NULLCOLLATIONA VT_I4 type parameter. It specifies how NULL values are treated in the sorting order.
Index Object Properties
DBPROP_INDEX_NULLSA VT_I4 type parameter. It specifies whether an index can use NULL values.
DBPROP_INDEX_PRIMARYKEYA VT_BOOL type parameter. If it's true, this index is based on the primary key.
DBPROP_INDEX_SORTBOOKMARKSA VT_BOOL type parameter. If it's true, the index sorts bookmarks.
DBPROP_INDEX_TEMPINDEXA VT_BOOL type parameter. If it's true, the index is temporary.
DBPROP_INDEX_TYPEA VT_I4 type parameter. It specifies the type of index mechanisms used by the data source.
DBPROP_INDEX_UNIQUEA VT_BOOL type parameter. If it's true, the index keys must be unique.
RowSet Object Properties
DBPROP_ABORTPRESERVA VT_BOOL type parameter. If it's true, the row set is preserved even after an aborted transaction.
DBPROP_APPENDONLYA VT_BOOL type parameter. If it's true, rows can only be added to the row set. You use this when creating new tables.
DBPROP_BLOCKINGSTORAGEOBJECTS A VT_BOOL type parameter. If it's true, storage objects could prevent other operations.
DBPROP_BOOKMARKSA VT_BOOL type parameter. If it's true, bookmarks can be used by the row set.
DBPROP_BOOKMARKSKIPPEDA VT_BOOL type parameter. If it's true, the GetRowsAt method can skip deleted bookmark rows.
DBPROP_BOOKMARKTYPEA VT_I4 type parameter. It specifies the type of bookmarks used: numeric or key.
DBPROP_CACHEDEFERREDA VT_BOOL type parameter. If it's true, deferred columns can be cached.
DBPROP_CANFETCHBACKWARDSA VT_BOOL type parameter. If it's true, methods used to get rows can retrieve rows before the current row.
RowSet Object Properties
DBPROP_CANHOLDROWSA VT_BOOL type parameter. If it's true, additional rows can be fetched when changes are pending.
DBPROP_CANSCROLLBACKWARDSA VT_BOOL type parameter. If it's true, you can retrieve rows before the current row.
DBPROP_CHANGEINSERTEDROWSA VT_BOOL type parameter. If it's true, you can make modifications to rows that have been added to the row set.
DBPROP_COLUMNRESTRICT *A VT_BOOL type parameter. If it's true, access can be restricted at the column level.
DBPROP_COMMANDTIMEOUTA VT_I4 type parameter. It specifies the amount of time before a command times out.
DBPROP_COMMITPRESERVEA VT_BOOL type parameter. If it's true, the row set is preserved after the transaction has been committed.
DBPROP_DEFERREDA VT_BOOL type parameter. If it's true, the column data is retrieved only when the GetData method is called.
DBPROP_DELAYSTORAGEOBJECTSA VT_BOOL type parameter. If it's true, updates to storage objects are delayed.
DBPROP_IAccessorA VT_BOOL type parameter. If it's true, the row set supports the Iaccessor interface.
DBPROP_IColumnsInfoA VT_BOOL type parameter. If it's true, the row set supports the IcolumnsInfo interface.
DBPROP_IColumnsRowsetA VT_BOOL type parameter. If it's true, the row set supports the IcolumnsRowset interface.
DBPROP_IConnectionPointContainer A VT_BOOL type parameter. If it's true, the row set supports the IconnectionPointContainer interface.
DBPROP_IConvertTypeA VT_BOOL type parameter. If it's true, the row set supports the IconvertType interface.
DBPROP_IRowsetA VT_BOOL type parameter. If it's true, the row set supports the IRowset interface.
DBPROP_IRowsetChangeA VT_BOOL type parameter. If it's true, the row set supports the IRowsetChAnge interface.
DBPROP_IRowsetIdentityA VT_BOOL type parameter. If it's true, the row set supports the IRowsetIdentity interface.
DBPROP_IRowsetInfoA VT_BOOL type parameter. If it's true, the row set supports the IRowsetInfo interface.
DBPROP_IRowsetLocateA VT_BOOL type parameter. If it's true, the row set supports the IRowsetLocate interface.
DBPROP_IRowsetResynchA VT_BOOL type parameter. If it's true, the row set supports the IRowsetResynch interface.
DBPROP_IRowsetScrollA VT_BOOL type parameter. If it's true, the row set supports the IRowsetScroll interface.
DBPROP_IRowsetUpdateA VT_BOOL type parameter. If it's true, the row set supports the IRowseUpdate interface.
DBPROP_ISupportErrorInfoA VT_BOOL type parameter. If it's true, the row set supports the IsupportErrorInfo interface.
DBPROP_ILockBytesA VT_BOOL type parameter. If it's true, the row set supports the ILockBytes storage interface.
DBPROP_ISequentialStreamA VT_BOOL type parameter. If it's true, the row set supports the IsequentialStream storage interface.
DBPROP_IStorageA VT_BOOL type parameter. If it's true, the row set supports the Istorage storage interface.
DBPROP_IStreamA VT_BOOL type parameter. If it's true, the row set supports the IStream storage interface.
DBPROP_IMMOBILEROWSA VT_BOOL type parameter. If it's true, updated rows will not be reordered.
DBPROP_LITERALBOOKMARKSA VT_BOOL type parameter. If it's true, bookmarks can be compared in an ordinal fashion.
DBPROP_LITERALIDENTITY *A VT_BOOL type parameter. If it's true, row handles can be compared to see whether they are the same.
RowSet Object Properties
DBPROP_MAXOPENROWS *A VT_I4 type parameter. It specifies the maximum number of rows that can be opened at once; if 0, there is no limit.
DBPROP_MAXPENDINGROWS *A VT_I4 type parameter. It specifies the maximum number of rows that can simultaneously have pending updates.
DBPROP_MAXROWS *A VT_I4 type parameter. It specifies the maximum number of rows that can be in a row set, and if 0, there is no limit.
DBPROP_MAYWRITECOLUMNA VT_BOOL type parameter. If it's true, a column is writable.
DBPROP_MEMORYUSAGEA VT_I4 type parameter. It specifies the percentage of memory that a row set can use. If it's 0, there is no limit.
DBPROP_NOTIFICATIONGRANULARITY A VT_I4 type parameter. It specifies when notification occurs.
DBPROP_NOTIFICATIONPHASES *A VT_I4 type parameter. It specifies when notifications are supported by the data provider.
DBPROP_NOTIFYCOLUMNSET *A VT_I4 type parameter. It specifies when notifications are generated by a column set.
DBPROP_NOTIFYROWDELETE *A VT_I4 type parameter. It specifies when notifications are generated by a row delete.
DBPROP_NOTIFYROWFIRSTCHANGE * A VT_I4 type parameter. It specifies when notifications are generated by a first row change.
DBPROP_NOTIFYROWINSERT *A VT_I4 type parameter. It specifies when notifications are generated by an insert.
DBPROP_NOTIFYROWRESYNCH *A VT_I4 type parameter. It specifies when notifications are generated by a row set resynchronization.
DBPROP_NOTIFYROWSETRELEASE *A VT_I4 type parameter. It specifies when notifications are generated by a row set release.
DBPROP_NOTIFYROWSETFETCHPOSITIONCHANGE* A VT_I4 type parameter. It specifies when notifications are generated by a position change.
RowSet Object Properties
DBPROP_NOTIFYROWUNDOCHANGE *A VT_I4 type parameter. It specifies when notifications are generated by an undo of a change.
DBPROP_NOTIFYROWUNDODELETE *A VT_I4 type parameter. It specifies when notifications are generated by an undo of a delete.
DBPROP_NOTIFYROWUNDOINSERT *A VT_I4 type parameter. It specifies when notifications are generated by an undo of an insert.
DBPROP_NOTIFYROWUPDATE *A VT_I4 type parameter. It specifies when notifications are generated by a row update.
DBPROP_ORDEREDBOOKMARKSA VT_BOOL type parameter. If it's true, bookmarks can be compared in an ordinal fashion.
DBPROP_OTHERINSERTA VT_BOOL type parameter. If it's true, rows inserted by others into a row set can be seen when they are inserted.
DBPROP_OTHERUPDATEDELETEA VT_BOOL type parameter. If it's true, changes by other users are visible.
DBPROP_OWNINSERTA VT_BOOL type parameter. If it's true, rows inserted by this user into the row set can be seen when they are inserted.
DBPROP_OWNUPDATEDELETEA VT_BOOL type parameter. If it's true, rows updated or deleted by this user are visible.
DBPROP_QUICKRESTARTA VT_BOOL type parameter. If it's true, the command that generated the row set is not re-executed when restarting.
DBPROP_REENTRANTEVENTS *A VT_BOOL type parameter. If it's true, reentrant events (events that can happen at the same time) are supported.
DBPROP_REMOVEDELETEDA VT_BOOL type parameter. If it's true, rows that have been marked for deletion are not included in the row set.
DBPROP_REPORTMULTIPLECHANGES * A VT_BOOL type parameter. If it's true, updates and deletes on row sets that affect multiple rows can be handled.
RowSet Object Properties
DBPROP_RETURNPENDINGINSERTS * A VT_BOOL type parameter. If it's true, rows with pending changes are included in the row set.
DBPROP_ROWRESTRICT *A VT_BOOL type parameter. If it's true, access to rows can be specified on a row basis.
DBPROP_ROWTHREADMODELA VT_I4 type parameter. It specifies the threading model used by row sets.
DBPROP_SERVERCURSORA VT_BOOL type parameter. If it's true, the data source supports server-side cursors.
DBPROP_STRONGIDENTITY *A VT_BOOL type parameter. If it's true, row handles to newly inserted rows can be compared with existing rows in an ordinal fashion.
DBPROP_TRANSACTEDOBJECTA VT_BOOL type parameter. If it's true, data changes for a column must be made through transactions.
DBPROP_UPDATABILITYA VT_I4 type parameter. It specifies the change methods supported by the row set.
Session Object Properties
DBPROP_SESS_AUTOCOMMITISOLEVELS A VT_I4 type parameter. It specifies the isolation level of transactions while the Autocommit mode is active.
Table Object Properties
DBPROP_TBL_TEMPTABLEA VT_BOOL type parameter. If it's true, this is a temporary table.

Now that you understand how to set and retrieve properties, and you know all the properties supported by OLE DB objects, you can begin to manipulate OLE DB objects at a higher level of detail. You will use these properties in the examples presented during the remainder of the book.

Transactions

Transactions control operations on a data source and encapsulate data source operations. A transaction starts before an operation begins and can commit the operation or abort the changes an operation makes. Transactions can coordinate multiuser operations on a data source. Typically, transactions enable a user to start some data source operation and to abort this operation at a later point. The use of transactions can also significantly improve application performance. The OLE DB TTransaction CoType is defined as follows:

TTransaction {
     interface IConnectionPointContainer;    // Required Interface
     interface ITransaction;                 // Required Interface
     interface ISupportErrorInfo;
};

The IConnectionPointContainer and ISupportErrorInfo are discussed in previous lessons (Day 19, "Navigating the Result of a Query," and Day 17, "Accessing a Data Source with OLE DB"), and error handling is discussed in more detail on Day 21, "OLE DB Error Handling." On Day 17 you learned that the Session object supports the following Transaction-related interfaces: ITransaction, ITransactionJoin, ITransactionLocal, and ITransactionObject. I'll discuss these interfaces in detail before examining the actual mechanics of using them.

The ITransaction Interface

The ITransaction interface controls a transaction; it commits transactions, aborts transactions, and obtains the current transaction status. The ITransaction interface is required by the Transaction object but optional for the Session object. The ITransaction interface defines the standard IUnknown interface methods QueryInterface, AddRef, and Release. The interface also provides three additional methods: Abort, Commit, and GetTransactionInfo. These methods are defined as follows:

HRESULT Abort(BOID *pboidReason, BOOL fRetaining, BOOL fAsync);
HRESULT Commit(BOOL fRetaining, DWORD grfCommitType, DWORD grfReserved);
HRESULT GetTransactionInfo(XACTTRANSINFO *pTransInfo);

The Abort method aborts a series of operations performed on a data source. For logging purposes, the pboidReason parameter specifies a reason that the transaction is being aborted. This parameter is a BOID type, which is defined as follows:

typedef struct BOID {
     BYTE rgb[16];
};

This simply defines a 16-byte buffer. If no reason is required, the BOID_NULL constant is used. The fRetaining parameter defines the retain behavior of the abort operation, which is sometimes referred to as Autocommit mode. If true, when the abort operation is carried out and subsequent transactions are created, the abort is performed in a separate (server-side) process thread. If false, a new thread is not created to carry out the abort. The fAsync flag determines whether the operation is carried out in the background. If true, the abort command returns immediately, and the abort processing happens in the background.

CAUTION
You must use the ITransactionOutcomeEvents interface to retrieve the results of the abort operation. If the abort is not asynchronous, you get the abort result in the return value from the Abort method call.

The Commit method commits a series of operations performed on a data source. The fRetaining parameter functions in the same way as it does in the Abort method, controlling the Autocommit mode. The grfCommitType parameter specifies the type of commit to be performed. Table 20.6 defines and describes the various types of commit parameters. The grfReserved parameter is reserved for future use and should always be 0.

Table 20.6  Commit Parameters
Commit Type
Description
XACTTC_ASYNCThe commit is performed in an asynchronous mode. The Commit method returns immediately, and commit processing is carried out in the background.
XACTTC_SYNC_PHASEONEThe Commit method returns after the first phase of the commit operation is performed. Commit methods are usually performed in two phases.
XACTTC_SYNC_PHASETWOThe Commit method returns after the second phase of the commit operation is performed; that is, it returns when the entire operation is complete.
XACTTC_SYNCThe commit is performed in a synchronous mode, the same as the XACTTC_SYNC_PHASETWO commit type.

The last method of the ITransation interface, GetTransactionInfo, retrieves information about a transaction. It returns a single parameter, pTransInfo, which is a pointer to an XACTTRANSINFO structure. This structure holds information about the transaction and is defined as follows:

typedef struct tagXACTTRANSINFO {
     XACTUOW   uow;
     ISOLEVEL  isoLevel;
     ULONG     isoFlags;
     DWORD     grfTCSupported;
     DWORD     grfRMSupported;
     DWORD     grfTCSupportedRetaining;
     DWORD     grfRMSupportedRetaining;
} XACTRANSINFO;

The uow field defines the level at which the transaction works, typically row. The XACTUOW type is defined as the BOID type that was defined earlier. The isoLevel field specifies the isolation level (discussed in more detail shortly) of this transaction. The isoFlags field is reserved for future use and will always be 0. The grfTCSupported field specifies special transactional-level flags. The grfRMSupported, grfTCSupportedRetaining, and grfRMSupportedRetaining are reserved for future use and will currently return 0. Unless you need to determine the isolation level of a previously started transaction, the GetTransactionInfo method currently does not return much more useful information.

The ITransactionLocal Interface

Just as you can use the ITransaction interface to end a transaction by committing or aborting it, you can use the ITransactionLocal interface of the Session object to begin a transaction. The ITransactionLocal interface is optional for the Session object and is supported only if the data provider supports transactions. The ITransactionLocal interface defines the standard IUnknown interface methods QueryInterface, AddRef, and Release. The interface also provides two additional methods: GetOptionsObject and StartTransaction. These methods are defined as follows:

HRESULT GetOptionsObject(ITransactionOptions **pOptionsInt);
HRESULT StartTransaction(ISOLEVEL isoLevel, ULONG isoFlagsResv,
                         ITransactionOptions *pIOptions,
                         ULONG *lNewTransLevel);

The StartTransaction method begins a set of operations that will be enveloped by a transaction. The isoLevel parameter specifies the isolation level of the transaction. The lisoFlagResv parameter is reserved for future isolation level flags, but for now it should be 0. The pIOptions parameter specifies a pointer to the ITransactionsOption interface. If options aren't required, you can pass a NULL value. Next I will discuss how to obtain and use the ITransactionsOption interface. The lNewTransLevel parameter returns the new transaction level.

The GetOptionsObject obtains access to the ITransactionOptions interface. A pointer to this interface is returned in the pOptionsInt parameter. What options, then, can be specified for a transaction?

The ITransactionOptions Interface

As I stated earlier, the ITransactionOptions interface specifies transaction-level options. This interface is accessed through the GetOptionsObject method. The ITransactionOptions interface defines the standard IUnknown interface methods QueryInterface, AddRef, and Release. Also, the interface provides two additional methods: SetOptions and GetOptions. These methods are defined as follows:

HRESULT SetOptions(XACTOPT *pOptions);
HRESULT GetOptions(XACTOPT *pOptions);

The names tell us that these methods set and retrieve option values. Both methods take a single parameter, a pointer to an XACTOPT structure, which defines the transaction options. This structure is defined as follows:

typedef struct tagXACTOPT {
     ULONG ulTImeout;
     unsigned char szDescription[MAX_TRANS_DESC];
} XACTOPT;

The ulTimeout field defines the number of milliseconds that the transaction can remain open before it's automatically aborted. If this value is 0, there will be no time limit. The szDescription field defines the transaction's description.

The ITransactionObject Interface

The ITransactionObject interface obtains access to a Transaction object by specifying its level. This interface is especially useful when using nested transactions (which are discussed shortly). This interface is provided through the Session object and is available only if transactions are supported. The ITransactionObject interface defines the standard IUnknown interface methods QueryInterface, AddRef, and Release. The interface provides one more method: GetTransactionObject. This method is defined as follows:

HRESULT GetTransactionObject(ULONG lTransLevel, ITransaction **ppITrans);

The lTransLevel specifies the transaction level for which you are searching. The pITrans parameter returns the level's corresponding Transaction object.

The ITransactionJoin Interface

The final transaction interface discussed today is the ITransactionJoin interface, which supports distributed transactions. This interface is provided through the Session object and is available only if transactions are supported. The ITransactionJoin interface defines the standard IUnknown interface methods QueryInterface, AddRef, and Release. The interface provides two additional methods: GetOptionsObject and JoinTransaction. These methods are defined as follows:

HRESULT GetOptionsObject(ITransactionOptions **ppITransOptions);
HRESULT JoinTransaction(IUnknown *punkDistTrans, ISOLEVEL isoLevel,
                        ULONG isoFlags, ITransactionOptions
                            *pITransOptions);

The GetOptionsObject retrieves distributed transaction options. The JoinTransaction method joins a distributed transaction, a transaction in which multiple clients can take part. Currently, the OLE DB ODBC data provider doesn't support distributed transactions.

Creating Transactions

To create a transaction that encapsulates a series of operations, you must first obtain access to the ITransactionLocal interface and then use the StartTransaction method to open the transaction. The transaction remains opened until it's committed or aborted. Listing 20.3 demonstrates how to use the StartTransaction method to open a database transaction. Note that for brevity, the code in Listing 20.3 doesn't check the return values. In your production code, be sure you test for the return values.


Listing 20.3  How to Start a Transaction

 1:    // Create a Session object...
 2:    pIDBInitialize->QueryInterface(IID_IDBCreateSession,
 3:                                   (void **) &pCreateSession);
 4:
 5:    // Create a Command object...
 6:    pCreateSession->CreateSession(NULL, IID_IDBCreateCommand,
 7:                                  (IUnknown **) &pCreateCommand);
 8:
 9:    // Access the ICommandText interface
10:    pCreateCommand->CreateCommand(NULL, IID_ICommandText,
11:                                  (IUnknown **) &pCommandText);
12:
13:    // Specify the command text
14:    pCommandText->SetCommandText(DBGUID_DBSQL, wCmdString);
15:
16:    // Access the Transaction Interface
17:    pCreateCommand->QueryInterface(IID_ITransactionLocal,
18:                                   (void **) &pTransLocal);
19:
20:    // Start the Transaction
21:    pTransLocal->StartTransaction(ISOLATIONLEVEL_SERIALIZABLE, 0,
22:                                  NULL, &lTransLevel);
23:    cout << "Transaction Level = " << lTransLevel << "\n";
24:
25:    // Execute the command
26:    pCommandText->Execute(NULL, IID_IRowset, NULL, &cNumRows,
27:                          (IUnknown **) &pRowset);
28:    // Remember to release the interface pointers.

Committing and Aborting Transactions

When the StartTransaction method is called, all database operations are saved until they are committed or aborted. When a transaction is committed, all the operations that have been saved are actually carried out on the data source. As you saw earlier, the commit operation enables you to specify whether it is carried out asynchronously, semi-synchronously, or synchronously and whether Autocommit mode is used. The state of any open row sets depends on the DBPROP_COMMITPRESERVE property (a Rowset object group property). If DBPROP_COMMITPRESERVE is true, the row set remains valid and is automatically synchronized when the transaction is committed or aborted; otherwise, the row set becomes invalid. This property is set on the basis of row set by row set. The Commit method is provided through the ITransaction interface, so you must access this interface to access the Commit method. The Commit method will commit the transaction at the current level. Listing 20.4 demonstrates how to commit the transaction started in Listing 20.3. Note that you should check the return value of QueryInterface in your production code.


Listing 20.4  How to Commit the Current Transaction

 1:    // Commit The Transaction
 2:    pCreateCommand->QueryInterface(IID_ITransaction,
                                          (void **) &pTrans);
 3:    pTrans->Commit(FALSE,XATTC_SYNC,0);

Aborting a transaction is just as easy. Listing 20.5 demonstrates how to use the Abort method to abort a transaction at the current level. Again, note that you should check the return value of QueryInterface in your production code.


Listing 20.5  How to Abort the Current Transaction

 1:    // Abort The Transaction
 2:    pCreateCommand->QueryInterface(IID_ITransactionLocal,
                                          (void **) &pTrans);
 3:    pTrans->Abort(NULL, FALSE, TRUE);

Nesting Transactions

If the data provider supports it, transactions can be nested. A nested transaction is created by starting a transaction while another transaction is already open. The inner transaction must be released before outer transactions can be committed or aborted.

Isolation Levels and Locking

OLE DB supports four levels of transaction isolation, which ensures coherent access to a data source. The transaction levels are Read Uncommitted, Read Committed, Repeatable Read, and Serializable.

With Read Committed isolation, any row sets that are created will view only rows that have been changed after those changes have been committed. Operations in this type of isolation level will see any rows that have been added or deleted. With Repeatable Read isolation, any changes to rows already read will not be seen, and any operation that deletes a row will not be seen. Any new rows that have been added will be visible. With Read Uncommitted, no attempt is made to isolate any types of changes. Rows that are retrieved will reflect the current database state. Finally, with Serializable isolation, the rows retrieved are guaranteed to be in the consistent state, reflecting only the changes of the current transaction.

Provider-specific, user-defined locking mechanisms implement these isolation levels. Table 20.7 defines the constants related to each isolation level. The isolation level is determined when the StartTransaction method starts a transaction.

Table 20.7  The OLE DB Isolation Levels
Isolation Constant
Description
ISOLATIONLEVEL_UNSPECIFIEDUsed only with the JoinTransaction method
ISOLATIONLEVEL_CHAOSPreserves changes made by higher-level transactions
ISOLATIONLEVEL_READUNCOMMITTED Read Uncommitted isolation
ISOLATIONLEVEL_BROWSERead Uncommitted isolation
ISOLATIONLEVEL_READCOMMITTEDRead Committed isolation
ISOLATIONLEVEL_CURSORSTABILITY Read Committed isolation
ISOLATIONLEVEL_REPEATABLEREAD Repeatable Read isolation
ISOLATIONLEVEL_SERIALIZABLESerializable isolation
ISOLATIONLEVEL_ISOLATEDSerializable isolation

The Index Object

The final OLE DB object today is the Index object. The Index object can directly access a data source index through a row set mechanism. Index objects access data source tables in a sorted manner and search for records, based on a key value. The TIndex CoType is defined as follows:

TIndex {
     interface IAccessor;           // Required Interface
     interface IColumnsInfo;        // Required Interface
     interface IConvertType;        // Required Interface
     interface IRowset;             // Required Interface
     interface IRowsetIndex;        // Required Interface
     interface IRowsetInfo;         // Required Interface
     interface IRowsetChange;
     interface ISupportErrorInfo;
};

You have already seen all these interfaces-except for the IRowsetIndex interface-in the context of the Rowset object. The next section describes the IRowsetIndex interface and explains how to implement the Index object.

The IRowsetIndex Interface

The IRowsetIndex interface is required by the Index object. It retrieves index information, searches for specific key values, and limits the set of visible rows to a range of key values. The IRowsetIndex interface defines the standard IUnknown interface methods QueryInterface, AddRef, and Release. The interface also provides three more methods: GetIndexInfo, Seek, and SetRange. These methods are defined as follows:

HRESULT GetIndexInfo(ULONG *plNumKeyCols, DBINDEXCOLUMNDESC
                     **pprdIdxColDesc, ULONG *plNumIdxProps,
                     DBPROPSET **prgIdxProps);
HRESULT Seek(HACCESSOR hAccessor, ULONG lNumKeys, void *pSeekData,
             DBSEEK dwSeekOpt);
HRESULT SetRange(HACCESSOR hAccessor, ULONG lNumStartKeyCols,
                 void *pStartKeyData, ULONG lNumEndKeyCols,
                 void *pEndKeyData, DBRANGE dwRangeOpt);

The GetIndexInfo method retrieves information about the index. The plNumKeyCols parameter returns the number of key columns in this index. The prdIdxColDesc parameter returns an array that describes each column. The plNumIdxProps parameter returns the number of elements in the prgIdxProps array. The prgIdxProps parameter returns an array that holds a collection of index properties.

TIP
Partial key searches are possible with the Seek method. You must supply the complete key set binding and then include only the partial key value for the key value.

The Seek method searches for a specific record in the index row set. The hAccessor parameter holds an Accessor to a set of bindings that describe the key structure. The lNumKeys parameter specifies the number of keys in the search criteria. The pSeekData parameter specifies the key set data for which you are searching. The dwSeekOpt parameter specifies the seek options. Seek options are outlined in Table 20.8.

Table 20.8  The OLE DB Seek Options
Seek Constant
Description
DBSEEK_FIRSTEQSearches for the first value that matches the key specified.
DBSEEK_LASTEQSearches for the last value that matches the key specified.
DBSEEK_GESearches for the first value that is greater than or equal to the key specified.
DBSEEK_GTSearches for the first value that is greater than the key specified.
DBSEEK_LESearches for the first value that is less than or equal to the key specified.
DBSEEK_LTSearches for the first value that is less than the key specified.

The SetRange method restricts the rows visible in the index row set to a range of key values. The hAccessor parameter holds an Accessor to a set of bindings that describe the key structure. The lNumStartKeyCols defines the number of key columns in the start range key. The pStartKeyData parameter specifies the start key data. The lNumEndKeyCols defines the number of key columns in the end range key. The pEndKeyData parameter specifies the end key data. The dwRangeOpt parameter specifies how the start and end keys will be used to limit the rows that will be visible. Table 20.9 defines the range options. These options can be combined with a logical OR operation.

Table 20.9  The OLE DB Range Options
Range Option
Description
DBRANGE_INCLUSIVESTARTIncludes all keys greater than or equal to the start key.
DBRANGE_EXCLUSIVESTARTIncludes all keys greater than the start key.
DBRANGE_INCLUSIVEENDIncludes all keys less than or equal to the end key.
DBRANGE_EXCLUSIVEENDIncludes all keys less than the end key.
DBRANGE_EXCLUDENULLSExcludes NULL values from the range.
DBRANGE_PREFIXUses the start key as a prefix, which enables faster searches on some data sources.
DBRANGE_MATCHIncludes only keys that are equal to the start key. The end key must be NULL if this flag is set.

Using the Index Object

Here's how to open and use an Index object:

  1. Open an index row set, using the IOpenRowset->OpenRowset method of the Session object.
  2. Retrieve the columns information, using the IColumnsInfo->GetColumnInfo method of the Index object.
  3. Create a binding structure that includes the rows that are part of the index. The dwFlags field of the column information structure will contain the flag value DBCOLUMNFLAGS_ISBOOKMARK if the column is a key field.
  4. Use the binding structure to create an Accessor, using the IAccessor->CreateAccessor method of the Index object.
  5. Use the IRowsetIndex interface methods to manipulate the index.

NOTE
Rather than rely on your OLE DB provider's support for the IRowsetIndex interface, you might need to use the appropriate SQL commands to retrieve specific rows or to retrieve rows in a specific order.

Summary

Day 20 focuses on three main topics: OLE DB properties and groups, the Transaction object, and the Index object. Today you learned how to retrieve and set property values and how to use the different types associated with properties. You reviewed the set of properties that OLE DB objects support and how to use these properties to determine whether a data source supports use of the SQL command language. You learned how to use the Transaction object to encapsulate your data source operations and to commit and abort transactions. Other transaction-related topics discussed today are nesting transaction, transaction isolation levels, and how to control locking. Today's final topic is the Index object, its associated interfaces, and how to use the Index object to search for specific rows in a row set that contain specific key values. Tomorrow's theme is how to integrate error handling into your OLE DB applications.

Q&A

This section answers some common questions related to today's topics.
Q
How can you use transactions to improve application performance?
A
When a transaction is opened, all operations that are performed are buffered until they are committed or aborted. In a client/server environment, using transactions can cut down on the network traffic. Only transactions that actually commit are transmitted to the server data source. This performance improvement doesn't come without a cost, however. In this case, the cost can be higher memory requirements (physical or disk space) on the client side. In a multiuser environment, though, this tradeoff can be worthwhile because it can yield significant performance improvements under the right conditions.
Q
How do isolation levels relate to specific locking schemes?
A
OLE DB doesn't specify the locking mechanisms used by a provider. The OLE DB specification leaves it to the data provider to implement its own appropriate locking methods that support the defined isolation levels. When using OLE DB, you should focus on isolation levels rather than on specific locking mechanisms, and you must use transactions to invoke these locking methodologies.
Q
How can you determine whether a data provider supports its own set of properties?
A
You can use the GetPropertyInfo method of the IDBProperties interface to return information about all properties supported by the data provider. This method returns a DBPROPINFOSET structure that contains information about each property supported by a data provider. You must navigate through this structure to determine the provider-specific properties it supports.

Workshop

The Workshop quiz questions test your understanding of today's material. (The answers appear in Appendix F, "Answers.") The exercises encourage you to apply the information you learned today to real-life situations.

Quiz

  1. List the major property groups.
  2. What structure returns the collection of property values?
  3. Name the property that determines the level of SQL command support provided by an OLE DB data provider?
  4. What method opens a transaction?
  5. What isolation level maintains the most consistent access to a row set in a multiuser environment?
  6. What property ensures that a row set is retained in a valid state after a transaction is closed?
  7. What Index object method searches for a specific key value in an index?

Exercises

  1. Review the properties supported by the OLE DB objects.
  2. Open the OLE DB ODBC provider Help file and review the provider-specific properties it supports.

© Copyright, Sams Publishing. All rights reserved.