IRowsetChange::InsertRow

Creates and initializes a new row.

HRESULT InsertRow (
   HCHAPTER      hChapter,
   HACCESSOR   hAccessor,
   void *            pData,
   HROW   *         phRow);

Parameters

hChapter

[in]
The chapter handle. For nonchaptered rowsets, hChapter is ignored.

hAccessor

[in]
The handle of the accessor to use.

If hAccessor is a null accessor (that is, an accessor for which cBindings in IAccessor::CreateAccessor was zero), then pData is ignored and the rows are initialized as specified in the Comments. Thus, the role of a null accessor is to construct a default row; it is a convenient way for a consumer to obtain a handle for a new row without having to set any values in that row initially.

pData

[in]
A pointer to memory containing the new data values, at offsets that correspond to the bindings in the accessor.

phRow

[out]
A pointer to memory in which to return the handle of the new row. If this is a null pointer, then no reference count is held on the row. Consumers should set this to null if they do not require the ability to make further changes to, or retrieve data from, the newly inserted row. Whether or not default or computed values from the server are available when calling GetData for this row handle depends on the setting of the DBPROP_SERVERDATAONINSERT. If InsertRow returns an error, and phRow is not a null pointer on input, *phRow is set to null on output and no row handle is returned.

Note Passing in a null pointer for phRow, or releasing the row handle returned in *phRow, does not release the row until the change is transmitted to the data source. If DBPROP_CANHOLDROWS is VARIANT_FALSE and the rowset is in deferred update mode, then in addition to freeing any reference counts on the hrow, the consumer must call IRowsetUpdate::Update in order to transmit the pending change to the data source before attempting to insert or retrieve any additional rows.

Return Code

S_OK
The method succeeded. The status of all columns bound by the accessor is set to DBSTATUS_S_OK or DBSTATUS_S_ISNULL.

DB_S_ERRORSOCCURRED
An error occurred while setting data for one or more columns, but data was successfully set for at least one column. To determine the columns for which values were invalid, the consumer checks the status values. For a list of status values that can be returned by this method, see "Status Values Used When Setting Data" in "Status" in Chapter 6.

E_FAIL
A provider-specific error occurred.

E_INVALIDARG
pData was a null pointer and hAccessor was not a null accessor.

E_OUTOFMEMORY
The provider was unable to allocate sufficient memory in which to instantiate the row.

E_UNEXPECTED
ITransaction::Commit or ITransaction::Abort was called and the object is in a zombie state.

DB_E_ABORTLIMITREACHED
The rowset was in immediate update mode and the row was not inserted due to reaching a limit on the server, such as a query execution timing out.

DB_E_BADACCESSORHANDLE
hAccessor was invalid.

DB_E_BADACCESSORTYPE
The specified accessor was not a row accessor or was a reference accessor.

DB_E_BADCHAPTER
The rowset was chaptered and hChapter was invalid.

The rowset was single-chaptered and the specified chapter was not the currently open chapter. The consumer must use the currently open chapter or release the currently open chapter before specifying a new chapter.

DB_E_CANCELED
The insertion was canceled during notification. The row was not inserted.

DB_E_CANTCONVERTVALUE
The data value for one or more columns couldn't be converted for reasons other than sign mismatch or data overflow, and the provider was unable to determine which columns couldn't be converted. Providers that can detect which columns could not be converted return DB_S_ERRORSOCCURRED and set the status flag for the columns that couldn't be converted to DBSTATUS_E_CANTCONVERTVALUE.

DB_E_DATAOVERFLOW
Conversion failed because the data value for one or more columns overflowed the type used by the provider and the provider was unable to determine which columns caused the overflow. Providers that can detect which columns caused the overflow return DB_S_ERRORSOCCURRED and set the status flag for the columns in violation to DBSTATUS_E_DATAOVERFLOW.

DB_E_ERRORSOCCURRED
An error occurred while setting data for one or more columns and data was not successfully set for any columns. To determine the columns for which values were invalid, the consumer checks the status values. For a list of status values that can be returned by this method, see "Status Values Used When Setting Data" in "Status" in Chapter 6.

DB_E_INTEGRITYVIOLATION
The data violated the integrity constraints for one or more columns of the rowset and the provider was unable to determine which columns violated the integrity constraints. Providers that can detect which columns violated the integrity constraints return DB_S_ERRORSOCCURRED and set the status flag for the columns in violation to DBSTATUS_E_INTEGRITYVIOLATION.

DB_E_MAXPENDCHANGESEXCEEDED
The number of rows that have pending changes has exceeded the limit specified by the DBPROP_MAXPENDINGROWS property.

DB_E_NOTREENTRANT
The provider called a method from IRowsetNotify in the consumer and the method has not yet returned.

DB_E_NOTSUPPORTED
The provider does not support this method.

DB_E_ROWLIMITEXCEEDED
Creating another row would have exceeded the total number of active rows supported by the rowset.

DB_E_ROWSNOTRELEASED
The consumer attempted to insert a new row before releasing previously retrieved row handles or transmitting pending changes to the data source, and DBPROP_CANHOLDROWS is VARIANT_FALSE.

DB_SEC_E_PERMISSIONDENIED
The consumer did not have sufficient permission to insert a new row. This error can be returned only if the value of the DBPROP_ROWRESTRICT property is VARIANT_TRUE. If the rowset is in delayed update mode, this error might not be returned until IRowsetUpdate::Update is called.

If this method performs deferred accessor validation and that validation takes place before any data is transferred, it can also return any of the following return codes for the applicable reasons listed in the corresponding DBBINDSTATUS values in IAccessor::CreateAccessor:

E_NOINTERFACE
DB_E_BADBINDINFO
DB_E_BADORDINAL
DB_E_BADSTORAGEFLAGS
DB_E_UNSUPPORTEDCONVERSION

Comments

InsertRow creates a new row and initializes its columns. If phRow is not a null pointer, it then returns the handle of this row to the consumer and sets its reference count to one. In delayed update mode, the row is created locally to the rowset and is transmitted to the data source only when IRowsetUpdate::Update is called. In immediate update mode, the row is immediately transmitted to the data source. For more information, see "Changing Data" in Chapter 5.

To the consumer, newly inserted rows are almost indistinguishable from other rows. For example, they can be deleted with DeleteRows and updated with SetData. However, methods that fetch rows might not be able to return them. For more information, see "Visibility of Pending Changes" and "Visibility of Transmitted Changes" in Chapter 5. Furthermore, they might not contain the correct values for computed columns, including bookmark columns on some providers.

For information about where rows are inserted in the rowset, see "Position of Inserted Rows" in Chapter 5.

The DBPROP_COLUMNRESTRICT and DBPROP_ROWRESTRICT properties affect how security is enforced and how security errors are returned. If DBPROP_COLUMNRESTRICT is VARIANT_TRUE, the consumer might not have write permission on some columns. If the consumer attempts to write to these columns, InsertRows returns a column status of DBSTATUS_E_PERMISSIONDENIED and a return code of DB_S_ERRORSOCCURRED. If the DBPROP_ROWRESTRICT property is VARIANT_TRUE, the consumer might not have permission to insert some rows. If the consumer attempts to insert one of these rows, InsertRows returns a code of DB_SEC_E_PERMISSIONDENIED and no new row is created.

When a row is created, initialization proceeds in an orderly fashion:

  1. The provider sets all columns to their default values. If there is no default value and the column is nullable, it sets the column to NULL. If the column is non-nullable, it sets the column status to DBSTATUS_E_UNAVAILABLE. If the provider is unable or unwilling to determine the default value of a column or whether that column is nullable, it sets the column status to DBSTATUS_E_UNAVAILABLE; the provider might be unwilling to determine default values and nullability if doing so requires a call to the data source.

    If the column status is DBSTATUS_E_UNAVAILABLE, the consumer can still send this value to the data source to use the default. In this case, the default is available after the insertion is transmitted to the data source. To see the default, the consumer must call GetLastVisibleData or RefreshVisibleData. However, if there is no default for the column and it is non-nullable, this will cause a schema violation.

  2. The provider calls IRowsetNotify::OnRowChange with DBREASON_ROW_INSERT if any consumer of the rowset is using notifications. This serves as a hook allowing, among other things, more complex nondeclarative default values to be set in the row. For more information about notifications, see IRowsetNotify.

  3. InsertRow does not further modify the column values if the accessor is a null accessor; it returns the handle to the newly created row.

  4. The provider uses the accessor, if it is not a null accessor, to set columns with the values provided by the consumer in *pData. During this process, the provider does not generate notifications like it does when setting data in SetData. This prevents, for example, DBREASON_COLUMN_SET notifications from being generated for a row that is not yet properly constructed. For a complete description of how InsertRow sets data, see "Setting Data" in Chapter 6.

    The provider is not required to compute the value of computed columns. If the provider does not compute the value of these columns but lets the data source do so, then the computed value is not available until after the change is transmitted to the data source—that is, after InsertRow is called in immediate update mode or after IRowsetUpdate::Update if InsertRow is called in delayed update mode. To retrieve the computed value, the consumer calls RefreshVisibleData or GetLastVisibleData in IRowsetRefresh. Note that bookmark columns are often computed, such as when the bookmark is the primary key or is a ROWID assigned by the data source.

Domain and schema validation is enforced as it is with SetData.

If InsertRow returns an error, it does not create a new row.

It is not recommended to use null accessors because some providers may not be able to determine default values and may not be able to identify a row inserted with all default values.

Here is an example of how one might write a projection-join to a temporary file:

#include <oledb.h>
#include <stddef.h>
int main() {
 IRowset   *pLeftRowset;
 IRowset   *pRightRowset;
 IAccessor   *pLeftRowsetAcc;
 IAccessor   *pRightRowsetAcc;
 IAccessor   *pJoinRowsetAcc;
 IRowsetChange *pJoinRowsetNew;
 ULONG    cSortedRows;
 HROW     rghLeftRows [500];
 HROW     rghRightRows [500];
 //...
 //< sort and prepare the rows >
 //..

 struct join {
  long *pl;
  double *pd;
  short  *pi;
 };

 static DBBINDING LeftBindings [1] = {
  {
   1,
   offsetof (join, pl),
   0,        // No length binding
   0,        // No status binding
   NULL,       // No TypeInfo
   NULL,       // No object
   NULL,       // No extensions
   DBPART_VALUE,
   DBMEMOWNER_PROVIDEROWNED,
   DBPARAMIO_NOTPARAM,
   sizeof (void*),
   0,
   DBTYPE_I4 | DBTYPE_BYREF,
   0,        // No precision
   0         // No scale
  }
 };
 static DBBINDING RightBindings [2]= {
  {
   1,
   offsetof (join, pd),
   0,        // No length binding
   0,        // No status binding
   NULL,       // No TypeInfo
   NULL,       // No object
   NULL,       // No extensions
   DBPART_VALUE,
   DBMEMOWNER_PROVIDEROWNED,
   DBPARAMIO_NOTPARAM,
   sizeof (void*),
   0,
   DBTYPE_R8 | DBTYPE_BYREF,
   0,        // No precision
   0         // No scale
  },
  {
   2,
   offsetof (join, pi),
   0,        // No length binding
   0,        // No status binding
   NULL,       // No TypeInfo
   NULL,       // No object
   NULL,       // No extensions
   DBPART_VALUE,
   DBMEMOWNER_PROVIDEROWNED,
   DBPARAMIO_NOTPARAM,
   sizeof (void*),
   0,
   DBTYPE_I2 | DBTYPE_BYREF,
   0,        // No precision
   0         // No scale
  }
 };


 static DBBINDING JoinBindings [3] = {
  {
   1,
   offsetof (join, pl),
   0,        // No length binding
   0,        // No status binding
   NULL,       // No TypeInfo
   NULL,       // No object
   NULL,       // No extensions
   DBPART_VALUE,
   DBMEMOWNER_PROVIDEROWNED,
   DBPARAMIO_NOTPARAM,
   sizeof (void*),
   0,
   DBTYPE_I4 | DBTYPE_BYREF,
   0,        // No precision
   0         // No scale
  },
  {
   2,
   offsetof (join, pd),
   0,        // No length binding
   0,        // No status binding
   NULL,       // No TypeInfo
   NULL,       // No object
   NULL,       // No extensions
   DBPART_VALUE,
   DBMEMOWNER_PROVIDEROWNED,
   DBPARAMIO_NOTPARAM,
   sizeof (void*),
   0,
   DBTYPE_R8 | DBTYPE_BYREF,
   0,        // No precision
   0         // No scale
  },
  {
   3,
   offsetof (join, pi),
   0,        // No length binding
   0,        // No status binding
   NULL,       // No TypeInfo
   NULL,       // No object
   NULL,       // No extensions
   DBPART_VALUE,
   DBMEMOWNER_PROVIDEROWNED,
   DBPARAMIO_NOTPARAM,
   sizeof (void*),
   0,
   DBTYPE_I2 | DBTYPE_BYREF,
   0,        // No precision
   0         // No scale
  }
 };

 HACCESSOR hLeft;
 HACCESSOR hRight;
 HACCESSOR hJoin;
 join  theJoin;

 pLeftRowsetAcc->CreateAccessor(DBACCESSOR_ROWDATA, 1, LeftBindings, 0, &hLeft,
            NULL);

 pRightRowsetAcc->CreateAccessor(DBACCESSOR_ROWDATA, 2, RightBindings, 0, &hRight,
             NULL);

 pJoinRowsetAcc->CreateAccessor(DBACCESSOR_ROWDATA, 3, JoinBindings, 0, &hJoin,
            NULL);

 for (ULONG j = 0; j < cSortedRows;  j++) {
  pLeftRowset->GetData(rghLeftRows[j], hLeft, &theJoin);
  pRightRowset->GetData(rghRightRows[j], hRight, &theJoin);
  pJoinRowsetNew->InsertRow(NULL, hJoin, &theJoin, NULL);
 } ;
};

See Also

IRowset::GetData, IRowsetChange::SetData, IRowsetUpdate::Undo, IRowsetUpdate::Update