IRowsetChange::InsertRow
Creates and initializes a new row.
Syntax
HRESULT InsertRow (
HCHAPTER hChapter,
HACCESSOR hAccessor,
void *pData,
HROW *phRow);
Parameters
hChapter
[in] The chapter handle. Providers are allowed to ignore this argument. For maximum interoperability, consumers should set hChapter to DB_NULL_HCHAPTER.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), 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. Passing an accessor with all columns set to DB_S_IGNORE is equivalent to passing a null accessor.
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, 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 IRowset::GetData for this row handle depends on the setting of the DBPROP_SERVERDATAONINSERT. If IRowsetChange::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 store. If DBPROP_CANHOLDROWS is VARIANT_FALSE and the rowset is in deferred update mode, then, in addition to freeing any reference counts on the row handle, the consumer must call IRowsetUpdate::Update in order to transmit the pending change to the data store 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.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. Some providers may return DB_E_BADACCESSORHANDLE instead of this error code when command accessors are passed to the rowset.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 could not 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.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, or the corresponding bit of DBPROP_UPDATABILITY is not set.Note
The spec, as of 2.1, does not require this return code if the corresponding bit is not set.
DB_E_ROWLIMITEXCEEDED
Creating another row would have exceeded the total number of active rows supported by the rowset.The provider does not allow a rowset containing more than DBPROP_MAXROWS rows, and the insert would cause the rowset to exceed this limit.
DB_E_ROWSNOTRELEASED
The consumer attempted to insert a new row before releasing previously retrieved row handles or transmitting pending changes to the data store, and DBPROP_CANHOLDROWS is VARIANT_FALSE.DB_SEC_E_PERMISSIONDENIED
The consumer did not have sufficient permission to insert a new row. If the rowset is in delayed update mode, this error might not be returned until IRowsetUpdate::Update is called.
Comments
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:
Note
E_NOINTERFACE
DB_E_BADBINDINFO
DB_E_BADORDINAL
DB_E_BADSTORAGEFLAGS
DB_E_UNSUPPORTEDCONVERSION
IRowsetChange::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 store only when IRowsetUpdate::Update is called. In immediate update mode, the row is immediately transmitted to the data store. For more information, see Changing Data.
To the consumer, newly inserted rows are almost indistinguishable from other rows. For example, they can be deleted with IRowsetChange::DeleteRows and updated with IRowsetChange::SetData. However, methods that fetch rows might not be able to return them. Furthermore, they might not contain the correct values for computed columns, including bookmark columns on some providers. For more information, see Visibility of Pending Changes and Visibility of Transmitted Changes. For information about where rows are inserted in the rowset, see Position of Inserted Rows.
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 will not have write permission on at least one column. If the consumer attempts to write to these columns, IRowsetChange::InsertRow 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, IRowsetChange::InsertRow 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. Conceptually, initialization consists of the following sequence of events.
Note
This sequence is not intended to specify how providers must implement initialization.
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 store.
If the column status is DBSTATUS_E_UNAVAILABLE, the consumer can still send this value to the data store to use the default. In this case, the default is available after the insertion is transmitted to the data store. To see the default, the consumer must call IRowsetRefresh::GetLastVisibleData or IRowsetRefresh::RefreshVisibleData. However, if there is no default for the column and it is non-nullable, this will cause a schema violation.
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.
IRowsetChange::InsertRow does not further modify the column values if the accessor is a null accessor; it returns the handle to the newly created row.
If the accessor is not a null accessor, the provider uses it to set columns with the values provided by the consumer in *pData. During this process, the provider does not generate notifications as it does when setting data in IRowsetChange::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 IRowsetChange::InsertRow sets data, see Setting Data.
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 store do so, the computed value is not available until after the change is transmitted to the data store ? that is, after IRowsetChange::InsertRow is called in immediate update mode or after IRowsetUpdate::Update if IRowsetChange::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 ? for example, when the bookmark is the primary key or is a ROWID assigned by the data store.
Domain and schema validation is enforced as it is with IRowsetChange::SetData.
If IRowsetChange::InsertRow returns an error, it does not create a new row.
When setting rowset column data values from a consumer's storage object, the provider is responsible for releasing the storage object. When the provider has finished using the consumer's storage object, it calls IUnknown::Release to release the pointer. If the consumer wants to ensure access to its storage object after IRowsetChange::InsertRow returns, it must call IUnknown::AddRef on the pointer before calling IRowsetChange::InsertRow.
It is the consumer's responsibility to release VARIANTs stored in *pData. The consumer should call the COM method VariantClear when a VARIANT is no longer needed.
The use of null accessors is not recommended 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);
} ;
return 0;
}