CRecordset class

Represents a set of records selected from a data source.

Syntax

class CRecordset : public CObject

Members

Public constructors

Name Description
CRecordset::CRecordset Constructs a CRecordset object. Your derived class must provide a constructor that calls this one.

Public methods

Name Description
CRecordset::AddNew Prepares for adding a new record. Call Update to complete the addition.
CRecordset::CanAppend Returns nonzero if new records can be added to the recordset via the AddNew member function.
CRecordset::CanBookmark Returns nonzero if the recordset supports bookmarks.
CRecordset::Cancel Cancels an asynchronous operation or a process from a second thread.
CRecordset::CancelUpdate Cancels any pending updates due to an AddNew or Edit operation.
CRecordset::CanRestart Returns nonzero if Requery can be called to run the recordset's query again.
CRecordset::CanScroll Returns nonzero if you can scroll through the records.
CRecordset::CanTransact Returns nonzero if the data source supports transactions.
CRecordset::CanUpdate Returns nonzero if the recordset can be updated (you can add, update, or delete records).
CRecordset::CheckRowsetError Called to handle errors generated during record fetching.
CRecordset::Close Closes the recordset and the ODBC HSTMT associated with it.
CRecordset::Delete Deletes the current record from the recordset. You must explicitly scroll to another record after the deletion.
CRecordset::DoBulkFieldExchange Called to exchange bulk rows of data from the data source to the recordset. Implements bulk record field exchange (Bulk RFX).
CRecordset::DoFieldExchange Called to exchange data (in both directions) between the field data members of the recordset and the corresponding record on the data source. Implements record field exchange (RFX).
CRecordset::Edit Prepares for changes to the current record. Call Update to complete the edit.
CRecordset::FlushResultSet Returns nonzero if there's another result set to be retrieved, when using a predefined query.
CRecordset::GetBookmark Assigns the bookmark value of a record to the parameter object.
CRecordset::GetDefaultConnect Called to get the default connection string.
CRecordset::GetDefaultSQL Called to get the default SQL string to execute.
CRecordset::GetFieldValue Returns the value of a field in a recordset.
CRecordset::GetODBCFieldCount Returns the number of fields in the recordset.
CRecordset::GetODBCFieldInfo Returns specific kinds of information about the fields in a recordset.
CRecordset::GetRecordCount Returns the number of records in the recordset.
CRecordset::GetRowsetSize Returns the number of records you wish to retrieve during a single fetch.
CRecordset::GetRowsFetched Returns the actual number of rows retrieved during a fetch.
CRecordset::GetRowStatus Returns the status of the row after a fetch.
CRecordset::GetSQL Gets the SQL string used to select records for the recordset.
CRecordset::GetStatus Gets the status of the recordset: the index of the current record and whether a final count of the records has been obtained.
CRecordset::GetTableName Gets the name of the table on which the recordset is based.
CRecordset::IsBOF Returns nonzero if the recordset has been positioned before the first record. There's no current record.
CRecordset::IsDeleted Returns nonzero if the recordset is positioned on a deleted record.
CRecordset::IsEOF Returns nonzero if the recordset has been positioned after the last record. There's no current record.
CRecordset::IsFieldDirty Returns nonzero if the specified field in the current record has been changed.
CRecordset::IsFieldNull Returns nonzero if the specified field in the current record is null (has no value).
CRecordset::IsFieldNullable Returns nonzero if the specified field in the current record can be set to null (having no value).
CRecordset::IsOpen Returns nonzero if Open has been called previously.
CRecordset::Move Positions the recordset to a specified number of records from the current record in either direction.
CRecordset::MoveFirst Positions the current record on the first record in the recordset. Test for IsBOF first.
CRecordset::MoveLast Positions the current record on the last record or on the last rowset. Test for IsEOF first.
CRecordset::MoveNext Positions the current record on the next record or on the next rowset. Test for IsEOF first.
CRecordset::MovePrev Positions the current record on the previous record or on the previous rowset. Test for IsBOF first.
CRecordset::OnSetOptions Called to set options (used on selection) for the specified ODBC statement.
CRecordset::OnSetUpdateOptions Called to set options (used on update) for the specified ODBC statement.
CRecordset::Open Opens the recordset by retrieving the table or performing the query that the recordset represents.
CRecordset::RefreshRowset Refreshes the data and status of the specified row(s).
CRecordset::Requery Runs the recordset's query again to refresh the selected records.
CRecordset::SetAbsolutePosition Positions the recordset on the record corresponding to the specified record number.
CRecordset::SetBookmark Positions the recordset on the record specified by the bookmark.
CRecordset::SetFieldDirty Marks the specified field in the current record as changed.
CRecordset::SetFieldNull Sets the value of the specified field in the current record to null (having no value).
CRecordset::SetLockingMode Sets the locking mode to "optimistic" locking (the default) or "pessimistic" locking. Determines how records are locked for updates.
CRecordset::SetParamNull Sets the specified parameter to null (having no value).
CRecordset::SetRowsetCursorPosition Positions the cursor on the specified row within the rowset.
CRecordset::SetRowsetSize Specifies the number of records you wish to retrieve during a fetch.
CRecordset::Update Completes an AddNew or Edit operation by saving the new or edited data on the data source.

Public data members

Name Description
CRecordset::m_hstmt Contains the ODBC statement handle for the recordset. Type HSTMT.
CRecordset::m_nFields Contains the number of field data members in the recordset. Type UINT.
CRecordset::m_nParams Contains the number of parameter data members in the recordset. Type UINT.
CRecordset::m_pDatabase Contains a pointer to the CDatabase object through which the recordset is connected to a data source.
CRecordset::m_strFilter Contains a CString that specifies a Structured Query Language (SQL) WHERE clause. Used as a filter to select only those records that meet certain criteria.
CRecordset::m_strSort Contains a CString that specifies a SQL ORDER BY clause. Used to control how the records are sorted.

Remarks

Known as "recordsets," CRecordset objects are typically used in two forms: dynasets and snapshots. A dynaset stays synchronized with data updates made by other users. A snapshot is a static view of the data. Each form represents a set of records fixed at the time the recordset is opened. When you scroll to a record in a dynaset, it reflects changes made to the record, either by other users or by other recordsets in your application.

Note

If you're working with the Data Access Objects (DAO) classes rather than the Open Database Connectivity (ODBC) classes, use class CDaoRecordset instead. For more information, see Overview: Database Programming.

To work with either kind of recordset, you typically derive an application-specific recordset class from CRecordset. Recordsets select records from a data source, and you can then:

  • Scroll through the records.

  • Update the records and specify a locking mode.

  • Filter the recordset to constrain which records it selects from those available on the data source.

  • Sort the recordset.

  • Parameterize the recordset to customize its selection with information not known until run time.

To use your class, open a database and construct a recordset object, passing the constructor a pointer to your CDatabase object. Then call the recordset's Open member function, where you can specify whether the object is a dynaset or a snapshot. Calling Open selects data from the data source. After the recordset object is opened, use its member functions and data members to scroll through the records and operate on them. The operations available depend on whether the object is a dynaset or a snapshot, whether it's updatable or read-only (this depends on the capability of the Open Database Connectivity (ODBC) data source), and whether you've implemented bulk row fetching. To refresh records that may have been changed or added since the Open call, call the object's Requery member function. Call the object's Close member function and destroy the object when you finish with it.

In a derived CRecordset class, record field exchange (RFX) or bulk record field exchange (Bulk RFX) is used to support reading and updating of record fields.

For more information about recordsets and record field exchange, see the articles Overview: Database Programming, Recordset (ODBC), Recordset: Fetching Records in Bulk (ODBC), and Record Field Exchange (RFX). For a focus on dynasets and snapshots, see the articles Dynaset and Snapshot.

Inheritance hierarchy

CObject

CRecordset

Requirements

Header: afxdb.h

CRecordset::AddNew

Prepares for adding a new record to the table.

virtual void AddNew();

Remarks

You must call the Requery member function to see the newly added record. The record's fields are initially Null. (In database terminology, Null means "having no value" and isn't the same as NULL in C++.) To complete the operation, you must call the Update member function. Update saves your changes to the data source.

Note

If you've implemented bulk row fetching, you can't call AddNew. This will result in a failed assertion. Although class CRecordset doesn't provide a mechanism for updating bulk rows of data, you can write your own functions by using the ODBC API function SQLSetPos. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

AddNew prepares a new, empty record using the recordset's field data members. After you call AddNew, set the values you want in the recordset's field data members. (You don't have to call the Edit member function for this purpose; use Edit only for existing records.) When you call Update, changed values in the field data members are saved on the data source.

Caution

If you scroll to a new record before you call Update, the new record is lost, and no warning is given.

If the data source supports transactions, you can make your AddNew call part of a transaction. For more information about transactions, see class CDatabase. Call CDatabase::BeginTrans before calling AddNew.

Note

For dynasets, new records are added to the recordset as the last record. Added records aren't added to snapshots; you must call Requery to refresh the recordset.

It's illegal to call AddNew for a recordset whose Open member function hasn't been called. A CDBException is thrown if you call AddNew for a recordset that can't be appended to. You can determine whether the recordset is updatable by calling CanAppend.

For more information, see the following articles: Recordset: How Recordsets Update Records (ODBC), Recordset: Adding, Updating, and Deleting Records (ODBC), and Transaction (ODBC).

Example

see Transaction: Performing a Transaction in a Recordset (ODBC).

CRecordset::CanAppend

Determines whether the previously opened recordset allows you to add new records.

BOOL CanAppend() const;

Return value

Nonzero if the recordset allows adding new records; otherwise 0. CanAppend will return 0 if you opened the recordset as read-only.

CRecordset::CanBookmark

Determines whether the recordset allows you to mark records using bookmarks.

BOOL CanBookmark() const;

Return value

Nonzero if the recordset supports bookmarks; otherwise 0.

Remarks

This function is independent of the CRecordset::useBookmarks option in the dwOptions parameter of the Open member function. CanBookmark indicates whether the given ODBC driver and cursor type support bookmarks. CRecordset::useBookmarks indicates whether bookmarks will be available, provided they're supported.

Note

Bookmarks aren't supported on forward-only recordsets.

For more information about bookmarks and recordset navigation, see the articles Recordset: Bookmarks and Absolute Positions (ODBC) and Recordset: Scrolling (ODBC).

CRecordset::Cancel

Requests that the data source cancel either an asynchronous operation in progress or a process from a second thread.

void Cancel();

Remarks

The MFC ODBC classes no longer use asynchronous processing; to perform an asynchronous operation, you must directly call the ODBC API function SQLSetConnectOption. For more information, see "Executing Functions Asynchronously" in the ODBC SDK Programmer's Guide.

CRecordset::CancelUpdate

Cancels any pending updates, caused by an Edit or AddNew operation, before Update is called.

void CancelUpdate();

Remarks

Note

This member function isn't applicable on recordsets that are using bulk row fetching, since such recordsets can't call Edit, AddNew, or Update. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

If automatic dirty field checking is enabled, CancelUpdate will restore the member variables to the values they had before Edit or AddNew was called; otherwise, any value changes will remain. By default, automatic field checking is enabled when the recordset is opened. To disable it, you must specify the CRecordset::noDirtyFieldCheck in the dwOptions parameter of the Open member function.

For more information about updating data, see Recordset: Adding, Updating, and Deleting Records (ODBC).

CRecordset::CanRestart

Determines whether the recordset allows restarting its query (to refresh its records) by calling the Requery member function.

BOOL CanRestart() const;

Return value

Nonzero if requery is allowed; otherwise 0.

CRecordset::CanScroll

Determines whether the recordset allows scrolling.

BOOL CanScroll() const;

Return value

Nonzero if the recordset allows scrolling; otherwise 0.

Remarks

For more information about scrolling, see Recordset: Scrolling (ODBC).

CRecordset::CanTransact

Determines whether the recordset allows transactions.

BOOL CanTransact() const;

Return value

Nonzero if the recordset allows transactions; otherwise 0.

Remarks

For more information, see Transaction (ODBC).

CRecordset::CanUpdate

Determines whether the recordset can be updated.

BOOL CanUpdate() const;

Return value

Nonzero if the recordset can be updated; otherwise 0.

Remarks

A recordset might be read-only if the underlying data source is read-only or if you specified CRecordset::readOnly in the dwOptions parameter when you opened the recordset.

CRecordset::CheckRowsetError

Called to handle errors generated during record fetching.

virtual void CheckRowsetError(RETCODE nRetCode);

Parameters

nRetCode
An ODBC API function return code. For details, see Remarks.

Remarks

This virtual member function handles errors that occur when records are fetched, and is useful during bulk row fetching. You may want to consider overriding CheckRowsetError to implement your own error handling.

CheckRowsetError is called automatically in a cursor navigation operation, such as Open, Requery, or any Move operation. It's passed the return value of the ODBC API function SQLExtendedFetch. The following table lists the possible values for the nRetCode parameter.

nRetCode Description
SQL_SUCCESS Function completed successfully; no additional information is available.
SQL_SUCCESS_WITH_INFO Function completed successfully, possibly with a nonfatal error. Additional information can be obtained by calling SQLError.
SQL_NO_DATA_FOUND All rows from the result set have been fetched.
SQL_ERROR Function failed. Additional information can be obtained by calling SQLError.
SQL_INVALID_HANDLE Function failed due to an invalid environment handle, connection handle, or statement handle. This indicates a programming error. No additional information is available from SQLError.
SQL_STILL_EXECUTING A function that was started asynchronously is still executing. By default, MFC will never pass this value to CheckRowsetError; MFC will continue calling SQLExtendedFetch until it no longer returns SQL_STILL_EXECUTING.

For more information about SQLError, see the Windows SDK. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

CRecordset::Close

Closes the recordset.

virtual void Close();

Remarks

The ODBC HSTMT and all memory the framework allocated for the recordset are deallocated. Usually after calling Close, you delete the C++ recordset object if it was allocated with new.

You can call Open again after calling Close. This lets you reuse the recordset object. The alternative is to call Requery.

Example

// Construct a snapshot object
CCustomer rsCustSet(NULL);

if (!rsCustSet.Open())
return;

// Use the snapshot ...

// Close the snapshot
rsCustSet.Close();

// Destructor is called when the function exits

CRecordset::CRecordset

Constructs a CRecordset object.

CRecordset(CDatabase* pDatabase = NULL);

Parameters

pDatabase
Contains a pointer to a CDatabase object or the value NULL. If not NULL and the CDatabase object's Open member function hasn't been called to connect it to the data source, the recordset attempts to open it for you during its own Open call. If you pass NULL, a CDatabase object is constructed and connected for you using the data source information you specified when you derived your recordset class with ClassWizard.

Remarks

You can either use CRecordset directly or derive an application-specific class from CRecordset. You can use ClassWizard to derive your recordset classes.

Note

A derived class must supply its own constructor. In the constructor of your derived class, call the constructor CRecordset::CRecordset, passing the appropriate parameters along to it.

Pass NULL to your recordset constructor to have a CDatabase object constructed and connected for you automatically. This is a useful shorthand that doesn't require you to construct and connect a CDatabase object prior to constructing your recordset.

Example

For more information, see Recordset: Declaring a Class for a Table (ODBC).

CRecordset::Delete

Deletes the current record.

virtual void Delete();

Remarks

After a successful deletion, the recordset's field data members are set to a Null value, and you must explicitly call one of the Move functions in order to move off the deleted record. Once you move off the deleted record, it's not possible to return to it. If the data source supports transactions, you can make the Delete call part of a transaction. For more information, see Transaction (ODBC).

Note

If you've implemented bulk row fetching, you can't call Delete. This will result in a failed assertion. Although class CRecordset doesn't provide a mechanism for updating bulk rows of data, you can write your own functions by using the ODBC API function SQLSetPos. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

Caution

The recordset must be updatable and there must be a valid record current in the recordset when you call Delete; otherwise, an error occurs. For example, if you delete a record but don't scroll to a new record before you call Delete again, Delete throws a CDBException.

Unlike AddNew and Edit, a call to Delete isn't followed by a call to Update. If a Delete call fails, the field data members are left unchanged.

Example

This example shows a recordset created on the frame of a function. The example assumes the existence of m_dbCust, a member variable of type CDatabase already connected to the data source.

// Create a derived CRecordset object
CCustomer rsCustSet(&m_dbCust);
rsCustSet.Open();

if (rsCustSet.IsEOF() || !rsCustSet.CanUpdate() ||
   !rsCustSet.CanTransact())
{
   return;
}

m_dbCust.BeginTrans();

// Perhaps scroll to a new record...
// Delete the current record
rsCustSet.Delete();

// Finished commands for this transaction
if (IDYES == AfxMessageBox(_T("Commit transaction?"), MB_YESNO))
m_dbCust.CommitTrans();
else // User changed mind
m_dbCust.Rollback();

CRecordset::DoBulkFieldExchange

Called to exchange bulk rows of data from the data source to the recordset. Implements bulk record field exchange (Bulk RFX).

virtual void DoBulkFieldExchange(CFieldExchange* pFX);

Parameters

pFX
A pointer to a CFieldExchange object. The framework will already have set up this object to specify a context for the field exchange operation.

Remarks

When bulk row fetching is implemented, the framework calls this member function to automatically transfer data from the data source to your recordset object. DoBulkFieldExchange also binds your parameter data members, if any, to parameter placeholders in the SQL statement string for the recordset's selection.

If bulk row fetching isn't implemented, the framework calls DoFieldExchange. To implement bulk row fetching, you must specify the CRecordset::useMultiRowFetch option of the dwOptions parameter in the Open member function.

Note

DoBulkFieldExchange is available only if you're using a class derived from CRecordset. If you've created a recordset object directly from CRecordset, you must call the GetFieldValue member function to retrieve data.

Bulk record field exchange (Bulk RFX) is similar to record field exchange (RFX). Data is automatically transferred from the data source to the recordset object. However, you can't call AddNew, Edit, Delete, or Update to transfer changes back to the data source. Class CRecordset currently doesn't provide a mechanism for updating bulk rows of data; however, you can write your own functions by using the ODBC API function SQLSetPos.

ClassWizard doesn't support bulk record field exchange; therefore, you must override DoBulkFieldExchange manually by writing calls to the Bulk RFX functions. For more information about these functions, see Record Field Exchange Functions.

For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC). For related information, see Record Field Exchange (RFX).

CRecordset::DoFieldExchange

Called to exchange data (in both directions) between the field data members of the recordset and the corresponding record on the data source. Implements record field exchange (RFX).

virtual void DoFieldExchange(CFieldExchange* pFX);

Parameters

pFX
A pointer to a CFieldExchange object. The framework will already have set up this object to specify a context for the field exchange operation.

Remarks

When bulk row fetching isn't implemented, the framework calls this member function to automatically exchange data between the field data members of your recordset object and the corresponding columns of the current record on the data source. DoFieldExchange also binds your parameter data members, if any, to parameter placeholders in the SQL statement string for the recordset's selection.

If bulk row fetching is implemented, the framework calls DoBulkFieldExchange. To implement bulk row fetching, you must specify the CRecordset::useMultiRowFetch option of the dwOptions parameter in the Open member function.

Note

DoFieldExchange is available only if you're using a class derived from CRecordset. If you've created a recordset object directly from CRecordset, you must call the GetFieldValue member function to retrieve data.

The exchange of field data, called record field exchange (RFX), works in both directions: from the recordset object's field data members to the fields of the record on the data source, and from the record on the data source to the recordset object.

The only action you must normally take to implement DoFieldExchange for your derived recordset class is to create the class with ClassWizard and specify the names and data types of the field data members. You might also add code to what ClassWizard writes to specify parameter data members or to deal with any columns you bind dynamically. For more information, see Recordset: Dynamically Binding Data Columns (ODBC).

When you declare your derived recordset class with ClassWizard, the wizard writes an override of DoFieldExchange for you, which resembles the following example:

void CCustomer::DoFieldExchange(CFieldExchange* pFX)
{
   pFX->SetFieldType(CFieldExchange::outputColumn);
   // Macros such as RFX_Text() and RFX_Int() are dependent on the
   // type of the member variable, not the type of the field in the database.
   // ODBC will try to automatically convert the column value to the requested type
   RFX_Long(pFX, _T("[CustomerID]"), m_CustomerID);
   RFX_Text(pFX, _T("[ContactFirstName]"), m_ContactFirstName);
   RFX_Text(pFX, _T("[PostalCode]"), m_PostalCode);
   RFX_Text(pFX, _T("[L_Name]"), m_L_Name);
   RFX_Long(pFX, _T("[BillingID]"), m_BillingID);

   pFX->SetFieldType(CFieldExchange::inputParam);
   RFX_Text(pFX, _T("Param"), m_strParam);
}

For more information about the RFX functions, see Record Field Exchange Functions.

For further examples and details about DoFieldExchange, see Record Field Exchange: How RFX Works. For general information about RFX, see Record Field Exchange.

CRecordset::Edit

Allows changes to the current record.

virtual void Edit();

Remarks

After you call Edit, you can change the field data members by directly resetting their values. The operation is completed when you call the Update member function to save your changes on the data source.

Note

If you've implemented bulk row fetching, you can't call Edit. This will result in a failed assertion. Although class CRecordset doesn't provide a mechanism for updating bulk rows of data, you can write your own functions by using the ODBC API function SQLSetPos. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

Edit saves the values of the recordset's data members. If you call Edit, make changes, then call Edit again, the record's values are restored to what they were before the first Edit call.

In some cases, you may want to update a column by making it Null (containing no data). To do so, call SetFieldNull with a parameter of TRUE to mark the field Null; this also causes the column to be updated. If you want a field to be written to the data source even though its value hasn't changed, call SetFieldDirty with a parameter of TRUE. This works even if the field had the value Null.

If the data source supports transactions, you can make the Edit call part of a transaction. Call CDatabase::BeginTrans before calling Edit and after the recordset has been opened. Also, calling CDatabase::CommitTrans isn't a substitute for calling Update to complete the Edit operation. For more information about transactions, see class CDatabase.

Depending on the current locking mode, the record being updated may be locked by Edit until you call Update or scroll to another record, or it may be locked only during the Edit call. You can change the locking mode with SetLockingMode.

The previous value of the current record is restored if you scroll to a new record before calling Update. A CDBException is thrown if you call Edit for a recordset that can't be updated or if there's no current record.

For more information, see the articles Transaction (ODBC) and Recordset: Locking Records (ODBC).

Example

// To edit a record, first set up the edit buffer
rsCustSet.Edit();

// Then edit field data members for the record
rsCustSet.m_BillingID = 2795;
rsCustSet.m_ContactFirstName = _T("Jones Mfg");

// Finally, complete the operation
if (!rsCustSet.Update())
{
   // Handle the failure to update
   AfxMessageBox(_T("Couldn't update record!"));
}

CRecordset::FlushResultSet

Retrieves the next result set of a predefined query (stored procedure), if there are multiple result sets.

BOOL FlushResultSet();

Return value

Nonzero if there are more result sets to be retrieved; otherwise 0.

Remarks

You should call FlushResultSet only when you're finished with the cursor on the current result set. When you retrieve the next result set by calling FlushResultSet, your cursor isn't valid on that result set; you should call the MoveNext member function after calling FlushResultSet.

If a predefined query uses an output parameter or input/output parameters, you must call FlushResultSet until it returns FALSE(the value 0), in order to obtain these parameter values.

FlushResultSet calls the ODBC API function SQLMoreResults. If SQLMoreResults returns SQL_ERROR or SQL_INVALID_HANDLE, then FlushResultSet will throw an exception. For more information about SQLMoreResults, see the Windows SDK.

Your stored procedure needs to have bound fields if you want to call FlushResultSet.

Example

The following code assumes that COutParamRecordset is a CRecordset-derived object based on a predefined query with an input parameter and an output parameter, and having multiple result sets. Note the structure of the DoFieldExchange override.

// DoFieldExchange override
//
// Only necessary to handle parameter bindings.
// Don't use CRecordset-derived class with bound
// fields unless all result sets have same schema
// OR there is conditional binding code.
void CCourses::DoFieldExchange(CFieldExchange* pFX)
{
   pFX->SetFieldType(CFieldExchange::outputParam);
   RFX_Long(pFX, _T("Param1"), m_nCountParam);
   // The "Param1" name here is a dummy name 
   // that is never used

   pFX->SetFieldType(CFieldExchange::inputParam);
   RFX_Text(pFX, _T("Param2"), m_strNameParam);
   // The "Param2" name here is a dummy name 
   // that is never used
}

 

// Assume db is an already open CDatabase object
CCourses rs(&m_dbCust);
rs.m_strNameParam = _T("History");

// Get the first result set
// NOTE: SQL Server requires forwardOnly cursor 
//       type for multiple rowset returning stored 
//       procedures
rs.Open(CRecordset::forwardOnly,
   _T("{? = CALL GetCourses( ? )}"),
   CRecordset::readOnly);

// Loop through all the data in the first result set
while (!rs.IsEOF())
{
   CString strFieldValue;
   for (short nIndex = 0; nIndex < rs.GetODBCFieldCount(); nIndex++)
   {
      rs.GetFieldValue(nIndex, strFieldValue);

      // TO DO: Use field value string.
   }
   rs.MoveNext();
}

// Retrieve other result sets...
while (rs.FlushResultSet())
{
   // must call MoveNext because cursor is invalid
   rs.MoveNext();

   while (!rs.IsEOF())
   {
      CString strFieldValue;
      for (short nIndex = 0; nIndex < rs.GetODBCFieldCount(); nIndex++)
      {
         rs.GetFieldValue(nIndex, strFieldValue);

         // TO DO: Use field value string.
      }
      rs.MoveNext();
   }
}


// All result sets have been flushed. Cannot
// use the cursor, but the output parameter,
// m_nCountParam, has now been written.
// Note that m_nCountParam is not valid until
// CRecordset::FlushResultSet has returned FALSE,
// indicating no more result sets will be returned.

// TO DO: Use m_nCountParam

// Cleanup
rs.Close();

CRecordset::GetBookmark

Obtains the bookmark value for the current record.

void GetBookmark(CDBVariant& varBookmark);

Parameters

varBookmark
A reference to a CDBVariant object representing the bookmark on the current record.

Remarks

To determine if bookmarks are supported on the recordset, call CanBookmark. To make bookmarks available if they're supported, you must set the CRecordset::useBookmarks option in the dwOptions parameter of the Open member function.

Note

If bookmarks are unsupported or unavailable, calling GetBookmark will result in an exception being thrown. Bookmarks aren't supported on forward-only recordsets.

GetBookmark assigns the value of the bookmark for the current record to a CDBVariant object. To return to that record at any time after moving to a different record, call SetBookmark with the corresponding CDBVariant object.

Note

After certain recordset operations, bookmarks may no longer be valid. For example, if you call GetBookmark followed by Requery, you may not be able to return to the record with SetBookmark. Call CDatabase::GetBookmarkPersistence to check whether you can safely call SetBookmark.

For more information about bookmarks and recordset navigation, see the articles Recordset: Bookmarks and Absolute Positions (ODBC) and Recordset: Scrolling (ODBC).

CRecordset::GetDefaultConnect

Called to get the default connection string.

virtual CString GetDefaultConnect();

Return value

A CString that contains the default connection string.

Remarks

The framework calls this member function to get the default connection string for the data source on which the recordset is based. ClassWizard implements this function for you by identifying the same data source you use in ClassWizard to get information about tables and columns. You'll probably find it convenient to rely on this default connection while developing your application. But the default connection may not be appropriate for users of your application. If that is the case, you should reimplement this function, discarding ClassWizard's version. For more information about connection strings, see Data Source (ODBC).

CRecordset::GetDefaultSQL

Called to get the default SQL string to execute.

virtual CString GetDefaultSQL();

Return value

A CString that contains the default SQL statement.

Remarks

The framework calls this member function to get the default SQL statement on which the recordset is based. This might be a table name or a SQL SELECT statement.

You indirectly define the default SQL statement by declaring your recordset class with ClassWizard, and ClassWizard performs this task for you.

If you need the SQL statement string for your own use, call GetSQL, which returns the SQL statement used to select the recordset's records when it was opened. You can edit the default SQL string in your class's override of GetDefaultSQL. For example, you could specify a call to a predefined query using a CALL statement. (Note, however, that if you edit GetDefaultSQL, you also need to modify m_nFields to match the number of columns in the data source.)

For more information, see Recordset: Declaring a Class for a Table (ODBC).

Caution

The table name will be empty if the framework could not identify a table name, if multiple table names were supplied, or if a CALL statement could not be interpreted. When you use a CALL statement, don't insert whitespace between the curly brace and the CALL keyword, nor before the curly brace or before the SELECT keyword in a SELECT statement.

CRecordset::GetFieldValue

Retrieves field data in the current record.

void GetFieldValue(
    LPCTSTR lpszName,
    CDBVariant& varValue,
    short nFieldType = DEFAULT_FIELD_TYPE);

void GetFieldValue(
    LPCTSTR lpszName,
    CStringA& strValue
);

void GetFieldValue(
    LPCTSTR lpszName,
    CStringW& strValue
);

void GetFieldValue(
    short nIndex,
    CDBVariant& varValue,
    short nFieldType = DEFAULT_FIELD_TYPE);

void GetFieldValue(
    short nIndex,
    CStringA& strValue);

void GetFieldValue(
    short nIndex,
    CStringW& strValue);

Parameters

lpszName
The name of a field.

varValue A reference to a CDBVariant object that will store the field's value.

nFieldType
The ODBC C data type of the field. Using the default value, DEFAULT_FIELD_TYPE, forces GetFieldValue to determine the C data type from the SQL data type, based on the following table. Otherwise, you can specify the data type directly or choose a compatible data type; for example, you can store any data type into SQL_C_CHAR.

C data type SQL data type
SQL_C_BIT SQL_BIT
SQL_C_UTINYINT SQL_TINYINT
SQL_C_SSHORT SQL_SMALLINT
SQL_C_SLONG SQL_INTEGER
SQL_C_FLOAT SQL_REAL
SQL_C_DOUBLE SQL_FLOATSQL_DOUBLE
SQL_C_TIMESTAMP SQL_DATESQL_TIMESQL_TIMESTAMP
SQL_C_CHAR SQL_NUMERICSQL_DECIMALSQL_BIGINTSQL_CHARSQL_VARCHARSQL_LONGVARCHAR
SQL_C_BINARY SQL_BINARYSQL_VARBINARYSQL_LONGVARBINARY

For more information about ODBC data types, see the topics "SQL Data Types" and "C Data Types" in Appendix D of the Windows SDK.

nIndex
The zero-based index of the field.

strValue
A reference to a CString object that will store the field's value converted to text, regardless of the field's data type.

Remarks

You can look up a field either by name or by index. You can store the field value in either a CDBVariant object or a CString object.

If you've implemented bulk row fetching, the current record is always positioned on the first record in a rowset. To use GetFieldValue on a record within a given rowset, you must first call the SetRowsetCursorPosition member function to move the cursor to the desired row within that rowset. Then call GetFieldValue for that row. To implement bulk row fetching, you must specify the CRecordset::useMultiRowFetch option of the dwOptions parameter in the Open member function.

You can use GetFieldValue to dynamically fetch fields at run time rather than statically binding them at design time. For example, if you've declared a recordset object directly from CRecordset, you must use GetFieldValue to retrieve the field data; record field exchange (RFX), or bulk record field exchange (Bulk RFX), isn't implemented.

Note

If you declare a recordset object without deriving from CRecordset, don't have the ODBC Cursor Library loaded. The cursor library requires that the recordset have at least one bound column; however, when you use CRecordset directly, none of the columns are bound. The member functions CDatabase::OpenEx and CDatabase::Open control whether the cursor library will be loaded.

GetFieldValue calls the ODBC API function SQLGetData. If your driver outputs the value SQL_NO_TOTAL for the actual length of the field value, GetFieldValue throws an exception. For more information about SQLGetData, see the Windows SDK.

Example

The following sample code illustrates calls to GetFieldValue for a recordset object declared directly from CRecordset.

// Create and open a database object;
// do not load the cursor library
CDatabase db;
db.OpenEx(NULL, CDatabase::forceOdbcDialog);

// Create and open a recordset object
// directly from CRecordset. Note that a
// table must exist in a connected database.
// Use forwardOnly type recordset for best
// performance, since only MoveNext is required
CRecordset rs(&db);
rs.Open(CRecordset::forwardOnly, _T("SELECT * FROM Customer"));

// Create a CDBVariant object to
// store field data
CDBVariant varValue;

// Loop through the recordset,
// using GetFieldValue and
// GetODBCFieldCount to retrieve
// data in all columns
short nFields = rs.GetODBCFieldCount();
while (!rs.IsEOF())
{
   for (short index = 0; index < nFields; index++)
   {
      rs.GetFieldValue(index, varValue);
      // do something with varValue
   }
   rs.MoveNext();
}

rs.Close();
db.Close();

Note

Unlike the DAO class CDaoRecordset, CRecordset doesn't have a SetFieldValue member function. If you create an object directly from CRecordset, it's effectively read-only.

For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

CRecordset::GetODBCFieldCount

Retrieves the total number of fields in your recordset object.

short GetODBCFieldCount() const;

Return value

The number of fields in the recordset.

Remarks

For more information about creating recordsets, see Recordset: Creating and Closing Recordsets (ODBC).

CRecordset::GetODBCFieldInfo

Obtains information about the fields in the recordset.

void GetODBCFieldInfo(
    LPCTSTR lpszName,
    CODBCFieldInfo& fieldinfo);

void GetODBCFieldInfo(
    short nIndex,
    CODBCFieldInfo& fieldinfo);

Parameters

lpszName
The name of a field.

fieldinfo
A reference to a CODBCFieldInfo structure.

nIndex
The zero-based index of the field.

Remarks

One version of the function lets you look up a field by name. The other version lets you look up a field by index.

For a description about the information returned, see the CODBCFieldInfo structure.

For more information about creating recordsets, see Recordset: Creating and Closing Recordsets (ODBC).

CRecordset::GetRecordCount

Determines the size of the recordset.

long GetRecordCount() const;

Return value

The number of records in the recordset; 0 if the recordset contains no records; or -1 if the record count can't be determined.

Remarks

Caution

The record count is maintained as a "high water mark," the highest-numbered record yet seen as the user moves through the records. The total number of records is only known after the user has moved beyond the last record. For performance reasons, the count isn't updated when you call MoveLast. To count the records yourself, call MoveNext repeatedly until IsEOF returns nonzero. Adding a record via CRecordset:AddNew and Update increases the count; deleting a record via CRecordset::Delete decreases the count.

CRecordset::GetRowsetSize

Obtains the current setting for the number of rows you wish to retrieve during a given fetch.

DWORD GetRowsetSize() const;

Return value

The number of rows to retrieve during a given fetch.

Remarks

If you're using bulk row fetching, the default rowset size when the recordset is opened is 25; otherwise, it's 1.

To implement bulk row fetching, you must specify the CRecordset::useMultiRowFetch option in the dwOptions parameter of the Open member function. To change the setting for the rowset size, call SetRowsetSize.

For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

CRecordset::GetRowsFetched

Determines how many records were retrieved after a fetch.

DWORD GetRowsFetched() const;

Return value

The number of rows retrieved from the data source after a given fetch.

Remarks

This is useful when you've implemented bulk row fetching. The rowset size normally indicates how many rows will be retrieved from a fetch. However, the total number of rows in the recordset also affects how many rows will be retrieved in a rowset. For example, if your recordset has 10 records with a rowset size setting of four, then looping through the recordset by calling MoveNext will result in the final rowset having only two records.

To implement bulk row fetching, you must specify the CRecordset::useMultiRowFetch option in the dwOptions parameter of the Open member function. To specify the rowset size, call SetRowsetSize.

For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

Example

CMultiCustomer rs(&m_dbCust);

// Set the rowset size
rs.SetRowsetSize(5);

// Open the recordset
rs.Open(CRecordset::dynaset, NULL, CRecordset::useMultiRowFetch);

// loop through the recordset by rowsets
while (!rs.IsEOF())
{
   for (int rowCount = 0; rowCount < (int)rs.GetRowsFetched(); rowCount++)
   {
      // do something
   }

   rs.MoveNext();
}

rs.Close();

CRecordset::GetRowStatus

Obtains the status for a row in the current rowset.

WORD GetRowStatus(WORD wRow) const;

Parameters

wRow
The one-based position of a row in the current rowset. This value can range from 1 to the size of the rowset.

Return value

A status value for the row. For details, see Remarks.

Remarks

GetRowStatus returns a value that indicates either any change in status to the row since it was last retrieved from the data source, or that no row corresponding to wRow was fetched. The following table lists the possible return values.

Status value Description
SQL_ROW_SUCCESS The row is unchanged.
SQL_ROW_UPDATED The row has been updated.
SQL_ROW_DELETED The row has been deleted.
SQL_ROW_ADDED The row has been added.
SQL_ROW_ERROR The row is unretrievable due to an error.
SQL_ROW_NOROW No row corresponds to wRow.

For more information, see the ODBC API function SQLExtendedFetch in the Windows SDK.

CRecordset::GetStatus

Determines the index of the current record in the recordset and whether the last record has been seen.

void GetStatus(CRecordsetStatus& rStatus) const;

Parameters

rStatus
A reference to a CRecordsetStatus object. For more information, see Remarks.

Remarks

CRecordset attempts to track the index, but under some circumstances this may not be possible. See GetRecordCount for an explanation.

The CRecordsetStatus structure has the following form:

struct CRecordsetStatus
{
    long m_lCurrentRecord;
    BOOL m_bRecordCountFinal;
};

The two members of CRecordsetStatus have the following meanings:

  • m_lCurrentRecord Contains the zero-based index of the current record in the recordset, if known. If the index can't be determined, this member contains AFX_CURRENT_RECORD_UNDEFINED (-2). If IsBOF is TRUE (empty recordset or attempt to scroll before first record), then m_lCurrentRecord is set to AFX_CURRENT_RECORD_BOF (-1). If on the first record, then it's set to 0, second record 1, and so on.

  • m_bRecordCountFinal Nonzero if the total number of records in the recordset has been determined. Generally this must be accomplished by starting at the beginning of the recordset and calling MoveNext until IsEOF returns nonzero. If this member is zero, the record count as returned by GetRecordCount, if not -1, is only a "high water mark" count of the records.

CRecordset::GetSQL

Call this member function to get the SQL statement that was used to select the recordset's records when it was opened.

const CString& GetSQL() const;

Return value

A const reference to a CString that contains the SQL statement.

Remarks

This will generally be a SQL SELECT statement. The string returned by GetSQL is read-only.

The string returned by GetSQL is typically different from any string you may have passed to the recordset in the lpszSQL parameter to the Open member function. This is because the recordset constructs a full SQL statement based on what you passed to Open, what you specified with ClassWizard, what you may have specified in the m_strFilter and m_strSort data members, and any parameters you may have specified. For details about how the recordset constructs this SQL statement, see Recordset: How Recordsets Select Records (ODBC).

Note

Call this member function only after calling Open.

CRecordset::GetTableName

Gets the name of the SQL table on which the recordset's query is based.

const CString& GetTableName() const;

Return value

A const reference to a CString that contains the table name, if the recordset is based on a table; otherwise, an empty string.

Remarks

GetTableName is only valid if the recordset is based on a table, not a join of multiple tables or a predefined query (stored procedure). The name is read-only.

Note

Call this member function only after calling Open.

CRecordset::IsBOF

Returns nonzero if the recordset has been positioned before the first record. There's no current record.

BOOL IsBOF() const;

Return value

Nonzero if the recordset contains no records or if you've scrolled backward before the first record; otherwise 0.

Remarks

Call this member function before you scroll from record to record to learn whether you've gone before the first record of the recordset. You can also use IsBOF along with IsEOF to determine whether the recordset contains any records or is empty. Immediately after you call Open, if the recordset contains no records, IsBOF returns nonzero. When you open a recordset that has at least one record, the first record is the current record and IsBOF returns 0.

If the first record is the current record and you call MovePrev, IsBOF will return nonzero. If IsBOF returns nonzero and you call MovePrev, an error occurs. If IsBOF returns nonzero, the current record is undefined, and any action that requires a current record will result in an error.

Example

This example uses IsBOF and IsEOF to detect the limits of a recordset as the code scrolls through the recordset in both directions.

// Open a recordset; first record is current
// Open a recordset; first record is current
CCustomer rsCustSet(&m_dbCust);
rsCustSet.Open();

if(rsCustSet.IsBOF())
   return;
   // The recordset is empty

// Scroll to the end of the recordset, past
// the last record, so no record is current
while (!rsCustSet.IsEOF())
   rsCustSet.MoveNext();

// Move to the last record
rsCustSet.MoveLast();

// Scroll to beginning of the recordset, before
// the first record, so no record is current
while(!rsCustSet.IsBOF())
   rsCustSet.MovePrev();

// First record is current again
rsCustSet.MoveFirst();

CRecordset::IsDeleted

Determines whether the current record has been deleted.

BOOL IsDeleted() const;

Return value

Nonzero if the recordset is positioned on a deleted record; otherwise 0.

Remarks

If you scroll to a record and IsDeleted returns TRUE (nonzero), then you must scroll to another record before you can perform any other recordset operations.

The result of IsDeleted depends on many factors, such as your recordset type, whether your recordset is updatable, whether you specified the CRecordset::skipDeletedRecords option when you opened the recordset, whether your driver packs deleted records, and whether there are multiple users.

For more information about CRecordset::skipDeletedRecords and driver packing, see the Open member function.

Note

If you've implemented bulk row fetching, you should not call IsDeleted. Instead, call the GetRowStatus member function. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

CRecordset::IsEOF

Returns nonzero if the recordset has been positioned after the last record. There's no current record.

BOOL IsEOF() const;

Return value

Nonzero if the recordset contains no records or if you've scrolled beyond the last record; otherwise 0.

Remarks

Call this member function as you scroll from record to record to learn whether you've gone beyond the last record of the recordset. You can also use IsEOF to determine whether the recordset contains any records or is empty. Immediately after you call Open, if the recordset contains no records, IsEOF returns nonzero. When you open a recordset that has at least one record, the first record is the current record and IsEOF returns 0.

If the last record is the current record when you call MoveNext, IsEOF will return nonzero. If IsEOF returns nonzero and you call MoveNext, an error occurs. If IsEOF returns nonzero, the current record is undefined, and any action that requires a current record will result in an error.

Example

See the example for IsBOF.

CRecordset::IsFieldDirty

Determines whether the specified field data member has been changed since Edit or AddNew was called.

BOOL IsFieldDirty(void* pv);

Parameters

pv
A pointer to the field data member whose status you want to check, or NULL to determine if any of the fields are dirty.

Return value

Nonzero if the specified field data member has changed since calling AddNew or Edit; otherwise 0.

Remarks

The data in all dirty field data members will be transferred to the record on the data source when the current record is updated by a call to the Update member function of CRecordset (following a call to Edit or AddNew).

Note

This member function isn't applicable on recordsets that are using bulk row fetching. If you've implemented bulk row fetching, then IsFieldDirty will always return FALSE and will result in a failed assertion. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

Calling IsFieldDirty will reset the effects of preceding calls to SetFieldDirty since the dirty status of the field is reevaluated. In the AddNew case, if the current field value differs from the pseudo null value, the field status is set dirty. In the Edit case, if the field value differs from the cached value, then the field status is set dirty.

IsFieldDirty is implemented through DoFieldExchange.

For more information on the dirty flag, see Recordset: How Recordsets Select Records (ODBC).

CRecordset::IsFieldNull

Returns nonzero if the specified field in the current record is Null (has no value).

BOOL IsFieldNull(void* pv);

Parameters

pv
A pointer to the field data member whose status you want to check, or NULL to determine if any of the fields are Null.

Return value

Nonzero if the specified field data member is flagged as Null; otherwise 0.

Remarks

Call this member function to determine whether the specified field data member of a recordset has been flagged as Null. (In database terminology, Null means "having no value" and isn't the same as NULL in C++.) If a field data member is flagged as Null, it's interpreted as a column of the current record for which there's no value.

Note

This member function isn't applicable on recordsets that are using bulk row fetching. If you've implemented bulk row fetching, then IsFieldNull will always return FALSE and will result in a failed assertion. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

IsFieldNull is implemented through DoFieldExchange.

CRecordset::IsFieldNullable

Returns nonzero if the specified field in the current record can be set to Null (having no value).

BOOL IsFieldNullable(void* pv);

Parameters

pv
A pointer to the field data member whose status you want to check, or NULL to determine if any of the fields can be set to a Null value.

Remarks

Call this member function to determine whether the specified field data member is "nullable" (can be set to a Null value; C++ NULL isn't the same as Null, which, in database terminology, means "having no value").

Note

If you've implemented bulk row fetching, you can't call IsFieldNullable. Instead, call the GetODBCFieldInfo member function to determine whether a field can be set to a Null value. You can always call GetODBCFieldInfo, regardless of whether you've implemented bulk row fetching. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

A field that can't be Null must have a value. If you attempt to set a such a field to Null when adding or updating a record, the data source rejects the addition or update, and Update will throw an exception. The exception occurs when you call Update, not when you call SetFieldNull.

Using NULL for the first argument of the function will apply the function only to outputColumn fields, not param fields. For instance, the call

SetFieldNull(NULL);

will set only outputColumn fields to NULL; param fields will be unaffected.

To work on param fields, you must supply the actual address of the individual param you want to work on, such as:

SetFieldNull(&m_strParam);

This means you can't set all param fields to NULL, as you can with outputColumn fields.

IsFieldNullable is implemented through DoFieldExchange.

CRecordset::IsOpen

Determines if the recordset is already open.

BOOL IsOpen() const;

Return value

Nonzero if the recordset object's Open or Requery member function has previously been called and the recordset hasn't been closed; otherwise 0.

CRecordset::m_hstmt

Contains a handle to the ODBC statement data structure, of type HSTMT, associated with the recordset.

Remarks

Each query to an ODBC data source is associated with an HSTMT.

Caution

Don't use m_hstmt before Open has been called.

Normally you don't need to access the HSTMT directly, but you might need it for direct execution of SQL statements. The ExecuteSQL member function of class CDatabase provides an example of using m_hstmt.

CRecordset::m_nFields

Contains the number of field data members in the recordset class; that is, the number of columns selected by the recordset from the data source.

Remarks

The constructor for the recordset class must initialize m_nFields with the correct number. If you haven't implemented bulk row fetching, ClassWizard writes this initialization for you when you use it to declare your recordset class. You can also write it manually.

The framework uses this number to manage interaction between the field data members and the corresponding columns of the current record on the data source.

Caution

This number must correspond to the number of "output columns" registered in DoFieldExchange or DoBulkFieldExchange after a call to SetFieldType with the parameter CFieldExchange::outputColumn.

You can bind columns dynamically, as explained in the article "Recordset: Dynamically Binding Data Columns." If you do so, you must increase the count in m_nFields to reflect the number of RFX or Bulk RFX function calls in your DoFieldExchange or DoBulkFieldExchange member function for the dynamically bound columns.

For more information, see the articles Recordset: Dynamically Binding Data Columns (ODBC) and Recordset: Fetching Records in Bulk (ODBC).

Example

see Record Field Exchange: Using RFX.

CRecordset::m_nParams

Contains the number of parameter data members in the recordset class; that is, the number of parameters passed with the recordset's query.

Remarks

If your recordset class has any parameter data members, the constructor for the class must initialize m_nParams with the correct number. The value of m_nParams defaults to 0. If you add parameter data members (which you must do manually) you must also manually add an initialization in the class constructor to reflect the number of parameters (which must be at least as large as the number of '' placeholders in your m_strFilter or m_strSort string).

The framework uses this number when it parameterizes the recordset's query.

Caution

This number must correspond to the number of "params" registered in DoFieldExchange or DoBulkFieldExchange after a call to SetFieldType with a parameter value of CFieldExchange::inputParam, CFieldExchange::param, CFieldExchange::outputParam, or CFieldExchange::inoutParam.

Example

See the articles Recordset: Parameterizing a Recordset (ODBC) and Record Field Exchange: Using RFX.

CRecordset::m_pDatabase

Contains a pointer to the CDatabase object through which the recordset is connected to a data source.

Remarks

This variable is set in two ways. Typically, you pass a pointer to an already connected CDatabase object when you construct the recordset object. If you pass NULL instead, CRecordset creates a CDatabase object for you and connects it. In either case, CRecordset stores the pointer in this variable.

Normally you won't directly need to use the pointer stored in m_pDatabase. If you write your own extensions to CRecordset, however, you might need to use the pointer. For example, you might need the pointer if you throw your own CDBExceptions. Or you might need it if you need to do something using the same CDatabase object, such as running transactions, setting timeouts, or calling the ExecuteSQL member function of class CDatabase to execute SQL statements directly.

CRecordset::m_strFilter

After you construct the recordset object, but before you call its Open member function, use this data member to store a CString containing a SQL WHERE clause.

Remarks

The recordset uses this string to constrain (or filter) the records it selects during the Open or Requery call. This is useful for selecting a subset of records, such as "all salespersons based in California" ("state = CA"). The ODBC SQL syntax for a WHERE clause is

WHERE search-condition

Don't include the WHERE keyword in your string. The framework supplies it.

You can also parameterize your filter string by placing '' placeholders in it, declaring a parameter data member in your class for each placeholder, and passing parameters to the recordset at run time. This lets you construct the filter at run time. For more information, see Recordset: Parameterizing a Recordset (ODBC).

For more information about SQL WHERE clauses, see SQL. For more information about selecting and filtering records, see Recordset: Filtering Records (ODBC).

Example

CCustomer rsCustSet(&m_dbCust);

// Set the filter
rsCustSet.m_strFilter = _T("L_Name = 'Flanders'");

// Run the filtered query
rsCustSet.Open(CRecordset::snapshot, _T("Customer"));

CRecordset::m_strSort

After you construct the recordset object, but before you call its Open member function, use this data member to store a CString containing a SQL ORDER BY clause.

Remarks

The recordset uses this string to sort the records it selects during the Open or Requery call. You can use this feature to sort a recordset on one or more columns. The ODBC SQL syntax for an ORDER BY clause is

ORDER BY sort-specification [, sort-specification]...

where a sort-specification is an integer or a column name. You can also specify ascending or descending order (the order is ascending by default) by appending "ASC" or "DESC" to the column list in the sort string. The selected records are sorted first by the first column listed, then by the second, and so on. For example, you might order a "Customers" recordset by last name, then first name. The number of columns you can list depends on the data source. For more information, see the Windows SDK.

Don't include the ORDER BY keyword in your string. The framework supplies it.

For more information about SQL clauses, see SQL. For more information about sorting records, see Recordset: Sorting Records (ODBC).

Example

CCustomer rsCustSet(&m_dbCust);

// Set the sort string
rsCustSet.m_strSort = _T("L_Name, ContactFirstName");

// Run the sorted query
rsCustSet.Open(CRecordset::snapshot, _T("Customer"));

CRecordset::Move

Moves the current record pointer within the recordset, either forward or backward.

virtual void Move(
    long nRows,
    WORD wFetchType = SQL_FETCH_RELATIVE);

Parameters

nRows
The number of rows to move forward or backward. Positive values move forward, toward the end of the recordset. Negative values move backward, toward the beginning.

wFetchType
Determines the rowset that Move will fetch. For details, see Remarks.

Remarks

If you pass a value of 0 for nRows, Move refreshes the current record; Move will end any current AddNew or Edit mode, and will restore the current record's value before AddNew or Edit was called.

Note

When you move through a recordset, you can't skip deleted records. See CRecordset::IsDeleted for more information. When you open a CRecordset with the skipDeletedRecords option set, Move asserts if the nRows parameter is 0. This behavior prevents the refresh of rows that are deleted by other client applications using the same data. See the dwOption parameter in Open for a description of skipDeletedRecords.

Move repositions the recordset by rowsets. Based on the values for nRows and wFetchType, Move fetches the appropriate rowset and then makes the first record in that rowset the current record. If you haven't implemented bulk row fetching, then the rowset size is always 1. When fetching a rowset, Move directly calls the CheckRowsetError member function to handle any errors resulting from the fetch.

Depending on the values you pass, Move is equivalent to other CRecordset member functions. In particular, the value of wFetchType may indicate a member function that is more intuitive and often the preferred method for moving the current record.

The following table lists the possible values for wFetchType, the rowset that Move will fetch based on wFetchType and nRows, and any equivalent member function corresponding to wFetchType.

wFetchType Fetched rowset Equivalent member function
SQL_FETCH_RELATIVE (the default value) The rowset starting nRows row(s) from the first row in the current rowset.
SQL_FETCH_NEXT The next rowset; nRows is ignored. MoveNext
SQL_FETCH_PRIOR The previous rowset; nRows is ignored. MovePrev
SQL_FETCH_FIRST The first rowset in the recordset; nRows is ignored. MoveFirst
SQL_FETCH_LAST The last complete rowset in the recordset; nRows is ignored. MoveLast
SQL_FETCH_ABSOLUTE If nRows > 0, the rowset starting nRows row(s) from the beginning of the recordset. If nRows < 0, the rowset starting nRows row(s) from the end of the recordset. If nRows = 0, then a beginning-of-file (BOF) condition is returned. SetAbsolutePosition
SQL_FETCH_BOOKMARK The rowset starting at the row whose bookmark value corresponds to nRows. SetBookmark

Note

For forward-only recordsets, Move is only valid with a value of SQL_FETCH_NEXT for wFetchType.

Caution

Calling Move throws an exception if the recordset has no records. To determine whether the recordset has any records, call IsBOF and IsEOF.

Note

If you've scrolled past the beginning or end of the recordset (IsBOF or IsEOF returns nonzero), calling a Move function will possibly throw a CDBException. For example, if IsEOF returns nonzero and IsBOF doesn't, then MoveNext will throw an exception, but MovePrev won't.

Note

If you call Move while the current record is being updated or added, the updates are lost without warning.

For more information about recordset navigation, see the articles Recordset: Scrolling (ODBC) and Recordset: Bookmarks and Absolute Positions (ODBC). For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC). For related information, see the ODBC API function SQLExtendedFetch in the Windows SDK.

Example

// rs is a CRecordset or a CRecordset-derived object

// Change the rowset size to 5
rs.SetRowsetSize(5);

// Open the recordset
rs.Open(CRecordset::dynaset, NULL, CRecordset::useMultiRowFetch);

// Move to the first record in the recordset
rs.MoveFirst();

// Move to the sixth record
rs.Move(5);
// Other equivalent ways to move to the sixth record:
rs.Move(6, SQL_FETCH_ABSOLUTE);
rs.SetAbsolutePosition(6);
// In this case, the sixth record is the first record in the next rowset,
// so the following are also equivalent:
rs.MoveFirst();
rs.Move(1, SQL_FETCH_NEXT);

rs.MoveFirst();
rs.MoveNext();

CRecordset::MoveFirst

Makes the first record in the first rowset the current record.

void MoveFirst();

Remarks

Regardless of whether bulk row fetching has been implemented, this will always be the first record in the recordset.

You don't have to call MoveFirst immediately after you open the recordset. At that time, the first record (if any) is automatically the current record.

Note

This member function isn't valid for forward-only recordsets.

Note

When you move through a recordset, you can't skip deleted records. See the IsDeleted member function for details.

Caution

Calling any of the Move functions throws an exception if the recordset has no records. To determine whether the recordset has any records, call IsBOF and IsEOF.

Note

If you call any of the Move functions while the current record is being updated or added, the updates are lost without warning.

For more information about recordset navigation, see the articles Recordset: Scrolling (ODBC) and Recordset: Bookmarks and Absolute Positions (ODBC). For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

Example

See the example for IsBOF.

CRecordset::MoveLast

Makes the first record in the last complete rowset the current record.

void MoveLast();

Remarks

If you haven't implemented bulk row fetching, your recordset has a rowset size of 1, so MoveLast moves to the last record in the recordset.

Note

This member function isn't valid for forward-only recordsets.

Note

When you move through a recordset, you can't skip deleted records. See the IsDeleted member function for details.

Caution

Calling any of the Move functions throws an exception if the recordset has no records. To determine whether the recordset has any records, call IsBOF and IsEOF.

Note

If you call any of the Move functions while the current record is being updated or added, the updates are lost without warning.

For more information about recordset navigation, see the articles Recordset: Scrolling (ODBC) and Recordset: Bookmarks and Absolute Positions (ODBC). For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

Example

See the example for IsBOF.

CRecordset::MoveNext

Makes the first record in the next rowset the current record.

void MoveNext();

Remarks

If you haven't implemented bulk row fetching, your recordset has a rowset size of 1, so MoveNext moves to the next record.

Note

When you move through a recordset, you can't skip deleted records. See the IsDeleted member function for details.

Caution

Calling any of the Move functions throws an exception if the recordset has no records. To determine whether the recordset has any records, call IsBOF and IsEOF.

Note

It's also recommended that you call IsEOF before calling MoveNext. For example, if you've scrolled past the end of the recordset, IsEOF will return nonzero; a subsequent call to MoveNext would throw an exception.

Note

If you call any of the Move functions while the current record is being updated or added, the updates are lost without warning.

For more information about recordset navigation, see the articles Recordset: Scrolling (ODBC) and Recordset: Bookmarks and Absolute Positions (ODBC). For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

Example

See the example for IsBOF.

CRecordset::MovePrev

Makes the first record in the previous rowset the current record.

void MovePrev();

Remarks

If you haven't implemented bulk row fetching, your recordset has a rowset size of 1, so MovePrev moves to the previous record.

Note

This member function isn't valid for forward-only recordsets.

Note

When you move through a recordset, you can't skip deleted records. See the IsDeleted member function for details.

Caution

Calling any of the Move functions throws an exception if the recordset has no records. To determine whether the recordset has any records, call IsBOF and IsEOF.

Note

It's also recommended that you call IsBOF before calling MovePrev. For example, if you've scrolled ahead of the beginning of the recordset, IsBOF will return nonzero; a subsequent call to MovePrev would throw an exception.

Note

If you call any of the Move functions while the current record is being updated or added, the updates are lost without warning.

For more information about recordset navigation, see the articles Recordset: Scrolling (ODBC) and Recordset: Bookmarks and Absolute Positions (ODBC). For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

Example

See the example for IsBOF.

CRecordset::OnSetOptions

Called to set options (used on selection) for the specified ODBC statement.

virtual void OnSetOptions(HSTMT hstmt);

Parameters

hstmt
The HSTMT of the ODBC statement whose options are to be set.

Remarks

Call OnSetOptions to set options (used on selection) for the specified ODBC statement. The framework calls this member function to set initial options for the recordset. OnSetOptions determines the data source's support for scrollable cursors and for cursor concurrency and sets the recordset's options accordingly. (Whereas OnSetOptions is used for selection operations, OnSetUpdateOptions is used for update operations.)

Override OnSetOptions to set options specific to the driver or the data source. For example, if your data source supports opening for exclusive access, you might override OnSetOptions to take advantage of that ability.

For more information about cursors, see ODBC.

CRecordset::OnSetUpdateOptions

Called to set options (used on update) for the specified ODBC statement.

virtual void OnSetUpdateOptions(HSTMT hstmt);

Parameters

hstmt
The HSTMT of the ODBC statement whose options are to be set.

Remarks

Call OnSetUpdateOptions to set options (used on update) for the specified ODBC statement. The framework calls this member function after it creates an HSTMT to update records in a recordset. (Whereas OnSetOptions is used for selection operations, OnSetUpdateOptions is used for update operations.) OnSetUpdateOptions determines the data source's support for scrollable cursors and for cursor concurrency and sets the recordset's options accordingly.

Override OnSetUpdateOptions to set options of an ODBC statement before that statement is used to access a database.

For more information about cursors, see ODBC.

CRecordset::Open

Opens the recordset by retrieving the table or performing the query that the recordset represents.

virtual BOOL Open(
    UINT nOpenType = AFX_DB_USE_DEFAULT_TYPE,
    LPCTSTR lpszSQL = NULL,
    DWORD dwOptions = none);

Parameters

nOpenType
Accept the default value, AFX_DB_USE_DEFAULT_TYPE, or use one of the following values from the enum OpenType:

  • CRecordset::dynaset A recordset with bi-directional scrolling. Opening the recordset determines the membership and ordering of the records, but changes made by other users to the data values are visible following a fetch operation. Dynasets are also known as keyset-driven recordsets.

  • CRecordset::snapshot A static recordset with bi-directional scrolling. Opening the recordset determines the membership and ordering of the records. Fetching a record determines the data values. Changes made by other users aren't visible until the recordset is closed and then reopened.

  • CRecordset::dynamic A recordset with bi-directional scrolling. Changes made by other users to the membership, ordering, and data values are visible following a fetch operation. Many ODBC drivers don't support this type of recordset.

  • CRecordset::forwardOnly A read-only recordset with only forward scrolling.

    For CRecordset, the default value is CRecordset::snapshot. The default-value mechanism allows the Visual C++ wizards to interact with both ODBC CRecordset and DAO CDaoRecordset, which have different defaults.

For more information about these recordset types, see Recordset (ODBC). For related information, see "Using Block and Scrollable Cursors" in the Windows SDK.

Caution

If the requested type isn't supported, the framework throws an exception.

lpszSQL
A string pointer containing one of the following:

  • A NULL pointer.

  • The name of a table.

  • A SQL SELECT statement (optionally with a SQL WHERE or ORDER BY clause).

  • A CALL statement specifying the name of a predefined query (stored procedure). Be careful to not insert whitespace between the curly brace and the CALL keyword.

For more information about this string, see the table and the discussion of ClassWizard's role under the Remarks section.

Note

The order of the columns in your result set must match the order of the RFX or Bulk RFX function calls in your DoFieldExchange or DoBulkFieldExchange function override.

dwOptions
A bitmask, which can specify a combination of the values listed below. Some of these are mutually exclusive. The default value is none.

  • CRecordset::none No options set. This parameter value is mutually exclusive with all other values. By default, the recordset can be updated with Edit or Delete and allows appending new records with AddNew. Updatability depends on the data source and the nOpenType option you specify. Optimization for bulk additions isn't available. Bulk row fetching won't be implemented. Deleted records won't be skipped during recordset navigation. Bookmarks aren't available. Automatic dirty field checking is implemented.

  • CRecordset::appendOnly Don't allow Edit or Delete on the recordset. Allow AddNew only. This option is mutually exclusive with CRecordset::readOnly.

  • CRecordset::readOnly Open the recordset as read-only. This option is mutually exclusive with CRecordset::appendOnly.

  • CRecordset::optimizeBulkAdd Use a prepared SQL statement to optimize adding many records at one time. Applies only if you aren't using the ODBC API function SQLSetPos to update the recordset. The first update determines which fields are marked dirty. This option is mutually exclusive with CRecordset::useMultiRowFetch.

  • CRecordset::useMultiRowFetch Implement bulk row fetching to allow multiple rows to be retrieved in a single fetch operation. This is an advanced feature designed to improve performance; however, bulk record field exchange isn't supported by ClassWizard. This option is mutually exclusive with CRecordset::optimizeBulkAdd. If you specify CRecordset::useMultiRowFetch, then the option CRecordset::noDirtyFieldCheck will be turned on automatically (double buffering won't be available); on forward-only recordsets, the option CRecordset::useExtendedFetch will be turned on automatically. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

  • CRecordset::skipDeletedRecords Skip all deleted records when navigating through the recordset. This will slow performance in certain relative fetches. This option isn't valid on forward-only recordsets. If you call Move with the nRows parameter set to 0, and the CRecordset::skipDeletedRecords option set, Move will assert. CRecordset::skipDeletedRecords is similar to driver packing, which means that deleted rows are removed from the recordset. However, if your driver packs records, then it will skip only those records that you delete; it won't skip records deleted by other users while the recordset is open. CRecordset::skipDeletedRecords will skip rows deleted by other users.

  • CRecordset::useBookmarks May use bookmarks on the recordset, if supported. Bookmarks slow data retrieval but improve performance for data navigation. Not valid on forward-only recordsets. For more information, see Recordset: Bookmarks and Absolute Positions (ODBC).

  • CRecordset::noDirtyFieldCheck Turn off automatic dirty field checking (double buffering). This will improve performance; however, you must manually mark fields as dirty by calling the SetFieldDirty and SetFieldNull member functions. Double buffering in class CRecordset is similar to double buffering in class CDaoRecordset. However, in CRecordset, you can't enable double buffering on individual fields; you either enable it for all fields or disable it for all fields. If you specify the option CRecordset::useMultiRowFetch, then CRecordset::noDirtyFieldCheck is turned on automatically; however, SetFieldDirty and SetFieldNull can't be used on recordsets that implement bulk row fetching.

  • CRecordset::executeDirect Don't use a prepared SQL statement. For improved performance, specify this option if the Requery member function will never be called.

  • CRecordset::useExtendedFetch Implement SQLExtendedFetch instead of SQLFetch. This is designed for implementing bulk row fetching on forward-only recordsets. If you specify the option CRecordset::useMultiRowFetch on a forward-only recordset, then CRecordset::useExtendedFetch will be turned on automatically.

  • CRecordset::userAllocMultiRowBuffers The user will allocate storage buffers for the data. Use this option with CRecordset::useMultiRowFetch if you want to allocate your own storage. Otherwise, the framework will automatically allocate the necessary storage. For more information, see Recordset: Fetching Records in Bulk (ODBC). Specifying CRecordset::userAllocMultiRowBuffers without specifying CRecordset::useMultiRowFetch results in a failed assertion.

Return value

Nonzero if the CRecordset object was successfully opened; otherwise 0 if CDatabase::Open (if called) returns 0.

Remarks

You must call this member function to run the query defined by the recordset. Before calling Open, you must construct the recordset object.

This recordset's connection to the data source depends on how you construct the recordset before calling Open. If you pass a CDatabase object to the recordset constructor that hasn't been connected to the data source, this member function uses GetDefaultConnect to attempt to open the database object. If you pass NULL to the recordset constructor, the constructor constructs a CDatabase object for you, and Open attempts to connect the database object. For details on closing the recordset and the connection under these varying circumstances, see Close.

Note

Access to a data source through a CRecordset object is always shared. Unlike the CDaoRecordset class, you can't use a CRecordset object to open a data source with exclusive access.

When you call Open, a query, usually a SQL SELECT statement, selects records based on criteria shown in the following table.

Value of the lpszSQL parameter Records selected are determined by Example
NULL The string returned by GetDefaultSQL.
SQL table name All columns of the table-list in DoFieldExchange or DoBulkFieldExchange. "Customer"
Predefined query (stored procedure) name The columns the query is defined to return. "{call OverDueAccts}"
SELECT column-list FROM table-list The specified columns from the specified table(s). "SELECT CustId, CustName FROM

Customer"

Caution

Don't insert extra whitespace in your SQL string. For example, if you insert whitespace between the curly brace and the CALL keyword, MFC will misinterpret the SQL string as a table name and incorporate it into a SELECT statement, which will result in an exception being thrown. Similarly, if your predefined query uses an output parameter, don't insert whitespace between the curly brace and the '' symbol. Finally, you must not insert whitespace before the curly brace in a CALL statement or before the SELECT keyword in a SELECT statement.

The usual procedure is to pass NULL to Open; in this case, Open calls GetDefaultSQL. If you're using a derived CRecordset class, GetDefaultSQL gives the table name(s) you specified in ClassWizard. You can instead specify other information in the lpszSQL parameter.

Whatever you pass, Open constructs a final SQL string for the query (the string may have SQL WHERE and ORDER BY clauses appended to the lpszSQL string you passed) and then executes the query. You can examine the constructed string by calling GetSQL after calling Open. For more details about how the recordset constructs a SQL statement and selects records, see Recordset: How Recordsets Select Records (ODBC).

The field data members of your recordset class are bound to the columns of the data selected. If any records are returned, the first record becomes the current record.

If you want to set options for the recordset, such as a filter or sort, specify these after you construct the recordset object but before you call Open. If you want to refresh the records in the recordset after the recordset is already open, call Requery.

For more information, including more examples, see Recordset (ODBC), Recordset: How Recordsets Select Records (ODBC), and Recordset: Creating and Closing Recordsets (ODBC).

Example

The following code examples show different forms of the Open call.

// rsSnap, rsLName, and rsDefault are CRecordset or CRecordset-derived 
// objects

// Open rs using the default SQL statement, implement bookmarks, and turn 
// off automatic dirty field checking
rsSnap.Open(CRecordset::snapshot, NULL, CRecordset::useBookmarks |
   CRecordset::noDirtyFieldCheck);

// Pass a complete SELECT statement and open as a dynaset
rsLName.Open(CRecordset::dynaset, _T("Select L_Name from Customer"));

// Accept all defaults
rsDefault.Open();

CRecordset::RefreshRowset

Updates the data and the status for a row in the current rowset.

void RefreshRowset(
    WORD wRow,
    WORD wLockType = SQL_LOCK_NO_CHANGE);

Parameters

wRow
The one-based position of a row in the current rowset. This value can range from zero to the size of the rowset.

wLockType
A value indicating how to lock the row after it has been refreshed. For details, see Remarks.

Remarks

If you pass a value of zero for wRow, then every row in the rowset will be refreshed.

To use RefreshRowset, you must have implemented bulk row fetching by specifying the CRecordset::useMulitRowFetch option in the Open member function.

RefreshRowset calls the ODBC API function SQLSetPos. The wLockType parameter specifies the lock state of the row after SQLSetPos has executed. The following table describes the possible values for wLockType.

wLockType Description
SQL_LOCK_NO_CHANGE (the default value) The driver or data source ensures that the row is in the same locked or unlocked state as it was before RefreshRowset was called.
SQL_LOCK_EXCLUSIVE The driver or data source locks the row exclusively. Not all data sources support this type of lock.
SQL_LOCK_UNLOCK The driver or data source unlocks the row. Not all data sources support this type of lock.

For more information about SQLSetPos, see the Windows SDK. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

CRecordset::Requery

Rebuilds (refreshes) a recordset.

virtual BOOL Requery();

Return value

Nonzero if the recordset was successfully rebuilt; otherwise 0.

Remarks

If any records are returned, the first record becomes the current record.

In order for the recordset to reflect the additions and deletions that you or other users are making to the data source, you must rebuild the recordset by calling Requery. If the recordset is a dynaset, it automatically reflects updates that you or other users make to its existing records (but not additions). If the recordset is a snapshot, you must call Requery to reflect edits by other users and additions and deletions.

For either a dynaset or a snapshot, call Requery anytime you want to rebuild the recordset using a new filter or sort, or new parameter values. Set the new filter or sort property by assigning new values to m_strFilter and m_strSort before calling Requery. Set new parameters by assigning new values to parameter data members before calling Requery. If the filter and sort strings are unchanged, you can reuse the query, which improves performance.

If the attempt to rebuild the recordset fails, the recordset is closed. Before you call Requery, you can determine whether the recordset can be requeried by calling the CanRestart member function. CanRestart doesn't guarantee that Requery will succeed.

Caution

Call Requery only after you've called Open.

Example

This example rebuilds a recordset to apply a different sort order.

CCustomer rsCustSet(&m_dbCust);

// Open the recordset
rsCustSet.Open();

// Use the recordset ...

// Set the sort order and Requery the recordset
rsCustSet.m_strSort = _T("L_Name, ContactFirstName");
if (!rsCustSet.CanRestart())
return;    // Unable to requery

if (!rsCustSet.Requery())
// Requery failed, so take action
AfxMessageBox(_T("Requery failed!"));

CRecordset::SetAbsolutePosition

Positions the recordset on the record corresponding to the specified record number.

void SetAbsolutePosition(long nRows);

Parameters

nRows
The one-based ordinal position for the current record in the recordset.

Remarks

SetAbsolutePosition moves the current record pointer based on this ordinal position.

Note

This member function isn't valid on forward-only recordsets.

For ODBC recordsets, an absolute position setting of 1 refers to the first record in the recordset; a setting of 0 refers to the beginning-of-file (BOF) position.

You can also pass negative values to SetAbsolutePosition. In this case, the recordset's position is evaluated from the end of the recordset. For example, SetAbsolutePosition( -1 ) moves the current record pointer to the last record in the recordset.

Note

Absolute position isn't intended to be used as a surrogate record number. Bookmarks are still the recommended way of retaining and returning to a given position, since a record's position changes when preceding records are deleted. In addition, you can't be assured that a given record will have the same absolute position if the recordset is re-created again because the order of individual records within a recordset isn't guaranteed unless it's created with a SQL statement using an ORDER BY clause.

For more information about recordset navigation and bookmarks, see the articles Recordset: Scrolling (ODBC) and Recordset: Bookmarks and Absolute Positions (ODBC).

CRecordset::SetBookmark

Positions the recordset on the record containing the specified bookmark.

void SetBookmark(const CDBVariant& varBookmark);

Parameters

varBookmark
A reference to a CDBVariant object containing the bookmark value for a specific record.

Remarks

To determine if bookmarks are supported on the recordset, call CanBookmark. To make bookmarks available if they're supported, you must set the CRecordset::useBookmarks option in the dwOptions parameter of the Open member function.

Note

If bookmarks are unsupported or unavailable, calling SetBookmark will result in an exception being thrown. Bookmarks aren't supported on forward-only recordsets.

To first retrieve the bookmark for the current record, call GetBookmark, which saves the bookmark value to a CDBVariant object. Later, you can return to that record by calling SetBookmark using the saved bookmark value.

Note

After certain recordset operations, you should check the bookmark persistence before calling SetBookmark. For example, if you retrieve a bookmark with GetBookmark and then call Requery, the bookmark may no longer be valid. Call CDatabase::GetBookmarkPersistence to check whether you can safely call SetBookmark.

For more information about bookmarks and recordset navigation, see the articles Recordset: Bookmarks and Absolute Positions (ODBC) and Recordset: Scrolling (ODBC).

CRecordset::SetFieldDirty

Flags a field data member of the recordset as changed or as unchanged.

void SetFieldDirty(void* pv, BOOL bDirty = TRUE);

Parameters

pv
Contains the address of a field data member in the recordset or NULL. If NULL, all field data members in the recordset are flagged. (C++ NULL isn't the same as Null in database terminology, which means "having no value.")

bDirty
TRUE if the field data member is to be flagged as "dirty" (changed). Otherwise FALSE if the field data member is to be flagged as "clean" (unchanged).

Remarks

Marking fields as unchanged ensures the field isn't updated and results in less SQL traffic.

Note

This member function isn't applicable on recordsets that are using bulk row fetching. If you've implemented bulk row fetching, then SetFieldDirty will result in a failed assertion. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

The framework marks changed field data members to ensure they'll be written to the record on the data source by the record field exchange (RFX) mechanism. Changing the value of a field generally sets the field dirty automatically, so you'll seldom need to call SetFieldDirty yourself, but you might sometimes want to ensure that columns will be explicitly updated or inserted regardless of what value is in the field data member.

Caution

Call this member function only after you've called Edit or AddNew.

Using NULL for the first argument of the function will apply the function only to outputColumn fields, not param fields. For instance, the call

SetFieldNull(NULL);

will set only outputColumn fields to NULL; param fields will be unaffected.

To work on param fields, you must supply the actual address of the individual param you want to work on, such as:

SetFieldNull(&m_strParam);

This means you can't set all param fields to NULL, as you can with outputColumn fields.

CRecordset::SetFieldNull

Flags a field data member of the recordset as Null (specifically having no value) or as non-Null.

void SetFieldNull(void* pv, BOOL bNull = TRUE);

Parameters

pv
Contains the address of a field data member in the recordset or NULL. If NULL, all field data members in the recordset are flagged. (C++ NULL isn't the same as Null in database terminology, which means "having no value.")

bNull
Nonzero if the field data member is to be flagged as having no value (Null). Otherwise 0 if the field data member is to be flagged as non-Null.

Remarks

When you add a new record to a recordset, all field data members are initially set to a Null value and flagged as "dirty" (changed). When you retrieve a record from a data source, its columns either already have values or are Null.

Note

Don't call this member function on recordsets that are using bulk row fetching. If you've implemented bulk row fetching, calling SetFieldNull results in a failed assertion. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

If you specifically wish to designate a field of the current record as not having a value, call SetFieldNull with bNull set to TRUE to flag it as Null. If a field was previously marked Null and you now want to give it a value, set its new value. You don't have to remove the Null flag with SetFieldNull. To determine whether the field is allowed to be Null, call IsFieldNullable.

Caution

Call this member function only after you've called Edit or AddNew.

Using NULL for the first argument of the function will apply the function only to outputColumn fields, not param fields. For instance, the call

SetFieldNull(NULL);

will set only outputColumn fields to NULL; param fields will be unaffected.

To work on param fields, you must supply the actual address of the individual param you want to work on, such as:

SetFieldNull(&m_strParam);

This means you can't set all param fields to NULL, as you can with outputColumn fields.

Note

When setting parameters to Null, a call to SetFieldNull before the recordset is opened results in an assertion. In this case, call SetParamNull.

SetFieldNull is implemented through DoFieldExchange.

CRecordset::SetLockingMode

Sets the locking mode to "optimistic" locking (the default) or "pessimistic" locking. Determines how records are locked for updates.

void SetLockingMode(UINT nMode);

Parameters

nMode
Contains one of the following values from the enum LockMode:

  • optimistic Optimistic locking locks the record being updated only during the call to Update.

  • pessimistic Pessimistic locking locks the record as soon as Edit is called and keeps it locked until the Update call completes or you move to a new record.

Remarks

Call this member function if you need to specify which of two record-locking strategies the recordset is using for updates. By default, the locking mode of a recordset is optimistic. You can change that to a more cautious pessimistic locking strategy. Call SetLockingMode after you construct and open the recordset object but before you call Edit.

CRecordset::SetParamNull

Flags a parameter as Null (specifically having no value) or as non-Null.

void SetParamNull(
    int nIndex,
    BOOL bNull = TRUE);

Parameters

nIndex
The zero-based index of the parameter.

bNull
If TRUE (the default value), the parameter is flagged as Null. Otherwise, the parameter is flagged as non-Null.

Remarks

Unlike SetFieldNull, you can call SetParamNull before you've opened the recordset.

SetParamNull is typically used with predefined queries (stored procedures).

CRecordset::SetRowsetCursorPosition

Moves the cursor to a row within the current rowset.

void SetRowsetCursorPosition(WORD wRow, WORD wLockType = SQL_LOCK_NO_CHANGE);

Parameters

wRow
The one-based position of a row in the current rowset. This value can range from 1 to the size of the rowset.

wLockType
Value indicating how to lock the row after it has been refreshed. For details, see Remarks.

Remarks

When implementing bulk row fetching, records are retrieved by rowsets, where the first record in the fetched rowset is the current record. In order to make another record within the rowset the current record, call SetRowsetCursorPosition. For example, you can combine SetRowsetCursorPosition with the GetFieldValue member function to dynamically retrieve the data from any record of your recordset.

To use SetRowsetCursorPosition, you must have implemented bulk row fetching by specifying the CRecordset::useMultiRowFetch option of the dwOptions parameter in the Open member function.

SetRowsetCursorPosition calls the ODBC API function SQLSetPos. The wLockType parameter specifies the lock state of the row after SQLSetPos has executed. The following table describes the possible values for wLockType.

wLockType Description
SQL_LOCK_NO_CHANGE (the default value) The driver or data source ensures that the row is in the same locked or unlocked state as it was before SetRowsetCursorPosition was called.
SQL_LOCK_EXCLUSIVE The driver or data source locks the row exclusively. Not all data sources support this type of lock.
SQL_LOCK_UNLOCK The driver or data source unlocks the row. Not all data sources support this type of lock.

For more information about SQLSetPos, see the Windows SDK. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

CRecordset::SetRowsetSize

Specifies the number of records you wish to retrieve during a fetch.

virtual void SetRowsetSize(DWORD dwNewRowsetSize);

Parameters

dwNewRowsetSize
The number of rows to retrieve during a given fetch.

Remarks

This virtual member function specifies how many rows you wish to retrieve during a single fetch when using bulk row fetching. To implement bulk row fetching, you must set the CRecordset::useMultiRowFetch option in the dwOptions parameter of the Open member function.

Note

Calling SetRowsetSize without implementing bulk row fetching will result in a failed assertion.

Call SetRowsetSize before calling Open to initially set the rowset size for the recordset. The default rowset size when implementing bulk row fetching is 25.

Note

Use caution when calling SetRowsetSize. If you're manually allocating storage for the data (as specified by the CRecordset::userAllocMultiRowBuffers option of the dwOptions parameter in Open), you should check whether you need to reallocate these storage buffers after you call SetRowsetSize, but before you perform any cursor navigation operation.

To obtain the current setting for the rowset size, call GetRowsetSize.

For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

CRecordset::Update

Completes an AddNew or Edit operation by saving the new or edited data on the data source.

virtual BOOL Update();

Return value

Nonzero if one record was successfully updated; otherwise 0 if no columns have changed. If no records were updated, or if more than one record was updated, an exception is thrown. An exception is also thrown for any other failure on the data source.

Remarks

Call this member function after a call to the AddNew or Edit member function. This call is required to complete the AddNew or Edit operation.

Note

If you've implemented bulk row fetching, you can't call Update. This will result in a failed assertion. Although class CRecordset doesn't provide a mechanism for updating bulk rows of data, you can write your own functions by using the ODBC API function SQLSetPos. For more information about bulk row fetching, see Recordset: Fetching Records in Bulk (ODBC).

Both AddNew and Edit prepare an edit buffer in which the added or edited data is placed for saving to the data source. Update saves the data. Only those fields marked or detected as changed are updated.

If the data source supports transactions, you can make the Update call (and its corresponding AddNew or Edit call) part of a transaction. For more information about transactions, see Transaction (ODBC).

Caution

If you call Update without first calling either AddNew or Edit, Update throws a CDBException. If you call AddNew or Edit, you must call Update before you call a Move operation or before you close either the recordset or the data source connection. Otherwise, your changes are lost without notification.

For details on handling Update failures, see Recordset: How Recordsets Update Records (ODBC).

Example

see Transaction: Performing a Transaction in a Recordset (ODBC).

See also

CObject class
Hierarchy chart
CDatabase class
CRecordView class