3.1.4.9.1 WriteTable (Opnum 3)

This method is called by a client to write entries to a catalog table.

 HRESULT WriteTable(
   [in] GUID* pCatalogIdentifier,
   [in] GUID* pTableIdentifier,
   [in] DWORD tableFlags,
   [in, size_is(cbQueryCellArray), unique] 
     char* pQueryCellArray,
   [in] ULONG cbQueryCellArray,
   [in, size_is(cbQueryComparison), unique] 
     char* pQueryComparison,
   [in] ULONG cbQueryComparison,
   [in] DWORD eQueryFormat,
   [in, size_is(cbTableDataFixedWrite)] 
     char* pTableDataFixedWrite,
   [in] ULONG cbTableDataFixedWrite,
   [in, size_is(cbTableDataVariable)] 
     char* pTableDataVariable,
   [in] ULONG cbTableDataVariable,
   [in, size_is(cbReserved1)] char* pReserved1,
   [in] ULONG cbReserved1,
   [in, size_is(cbReserved2)] char* pReserved2,
   [in] ULONG cbReserved2,
   [in, size_is(cbReserved3)] char* pReserved3,
   [in] ULONG cbReserved3,
   [out, size_is(, *pcbTableDetailedErrors)] 
     char** ppTableDetailedErrors,
   [out] ULONG* pcbTableDetailedErrors
 );

pCatalogIdentifier:  The catalog identifier of the COMA catalog. MUST be {6E38D3C4-C2A7-11D1-8DEC-00C04FC2E0C7}.

pTableIdentifier:  The table identifier for one of the tables defined in section 3.1.1.3 for the negotiated catalog version.

tableFlags:  An fTableFlags (section 2.2.1.1) value supported (see section 3.1.1.2.3) by the table identified by pTableIdentifier.

pQueryCellArray:  A QueryCellArray structure, marshaled in the negotiated format as specified in section 2.2.1.5, for a supported query (see section 3.1.1.2.2) on the table identified by pTableIdentifier.

cbQueryCellArray:  The size in bytes of pQueryCellArray.

pQueryComparison:  A QueryComparisonData (section 2.2.1.6) structure for a supported query (see section 3.1.1.2) on the table identified by pTableIdentifier.

cbQueryComparison:  The size in bytes of pQueryComparison.

eQueryFormat:  MUST be set to eQUERYFORMAT_1 (0x00000001).

pTableDataFixedWrite:  A TableDataFixedWrite structure, marshaled as specified in section 2.2.1.13.

cbTableDataFixedWrite:  The length in bytes of the TableDataFixedWrite structure passed in pTableDataFixedWrite.

pTableDataVariable:  A TableDataVariable structure, marshaled as specified in section 2.2.1.15.

cbTableDataVariable:  The length in bytes of the TableDataVariable structure passed in pTableDataVariable.

pReserved1: MUST be set to NULL when sent and MUST be ignored on receipt.

cbReserved1: MUST be set to zero when sent and MUST be ignored on receipt.

pReserved2: MUST be set to NULL when sent and MUST be ignored on receipt.

cbReserved2: MUST be set to zero when sent and MUST be ignored on receipt.

pReserved3: MUST be set to NULL when sent and MUST be ignored on receipt.

cbReserved3: MUST be set to zero when sent and MUST be ignored on receipt.

ppTableDetailedErrors:  A pointer to a variable that, upon successful completion, MUST be set to NULL, and that, upon partial failure, MAY<297> be set to a TableDetailedErrorArray structure, marshaled as specified in section 2.2.1.17.

pcbTableDetailedErrors:  A pointer to a variable that, upon completion, MUST be set to the length in bytes of the TableDetailedErrorArray structure returned in ppTableDetailedErrors if such a structure was returned and MUST be set to zero otherwise.

Return Values:  This method MUST return S_OK (0x00000000) on success, and a failure result, as specified in [MS-ERREF] section 2.1, on failure. All failure results MUST be treated identically, with the exception of E_DETAILEDERRORS (0x80110802).

Upon receiving a call to this method, the server MUST verify that catalog version negotiation has been performed by checking the negotiated catalog version (see section 3.1.1.5), and fail the call if not.

The server then MUST perform parameter validation as follows:

  • The server SHOULD<298> verify that the value referenced by pCatalogIdentifier is the catalog identifier of the COMA catalog {6E38D3C4-C2A7-11D1-8DEC-00C04FC2E0C7}, and fail the call if not.

  • The server SHOULD<299> verify that the value referenced by pTableIdentifier is the table identifier of a table defined in section 3.1.1.3 for the negotiated catalog version, and fail the call if not.

  • The server SHOULD<300> verify that tableFlags is a supported table flags value (see section 3.1.1.2.3) for the table identified by pTableIdentifier, and fail the call if not.

  • The server SHOULD<301> verify that the query represented by the parameters pQueryCellArray, cbQueryCellArray, pQueryComparison, and cbQueryComparison are a supported query (see section 3.1.1.2.2) on the table identified by pTableIdentifier, and fail the call if not.

  • The server MUST verify that all other parameters meet the preceding constraints.

The server then SHOULD verify that the client is authorized to write to the table identified by pTableIdentifier. Authorization MAY<302> be determined differently for different tables.

The server then MAY verify that previously in the session, ICatalogTableRead::ReadTable (section 3.1.4.8.1) was called for the same table and with an identical query.

The parameters pTableDataFixedWrite, cbTableDataFixedWrite, pTableDataVariable, and cbTableDataVariable specify writes to zero or more entries in the table identified by pTableIdentifier. Each TableEntryFixedWrite (section 2.2.1.12) structure and the corresponding TableEntryVariable (section 2.2.1.14) together specify a write to a single entry, known as an entry write. The server MUST verify that these parameters are a properly formatted representation of zero entry writes for the table and fail the call if not. A call to WriteTable specifying zero entry writes is explicitly legal, although it results in no changes to the catalog. If a server receives a call specifying zero entry writes, it MUST NOT make any changes to the catalog and MUST return S_OK (0x00000000).

The server MUST validate and attempt to perform the specified entry writes, as described later in this section. If validation fails for any of the entry writes (for example, if performing the entry write would result in the constraints for one or more of the properties in the table being violated), the server MAY<303> add one or more TableDetailedError (section 2.2.1.16) records to the detailed error results, using the zero-based index of the entry write and the zero-based index of a property to indicate to the client which specific change caused the failure. Additionally, if the server fails to perform an entry write (for example, if the server is unable to write a property value to its data store), the server MAY add one or more TableDetailedError records. Whether the server returns immediately upon generating a TableDetailedError or continues to validate entry writes in order to generate a more complete record of the reason for failure is implementation-specific.<304>

For the following description, each entry write is an add, update, or remove, indicated by the value of the Action field of the TableEntryFixedWrite structure for the entry write, taken from the eTableEntryAction (section 2.2.1.11) enumeration.

The server MUST validate the entry writes and, for updates and removes, select a target from the existing entries in the table, as follows:

  • If one or more adds are specified, the server SHOULD<305> verify that adds are supported for the table, as specified in the table's definition (as specified in section 3.1.1.3), and fail the call if not.

  • If one or more updates are specified, the server SHOULD<306> verify that updates are supported for the table, as specified in the table's definition (as specified in section 3.1.1.3), and fail the call if not.

  • If one or more removes are specified, the server SHOULD<307> verify that removes are supported for the table, as specified in the table's definition (as specified in section 3.1.1.3), and fail the call if not.

  • For each entry write, the server MUST perform the following:

    • For each QueryCell (section 2.2.1.4) structure and its corresponding comparison value (together known as a query element) in the query represented by the parameters pQueryCellArray, cbQueryCellArray, pQueryComparison, and cbQueryComparison, the server MUST perform the following:

      • If the IndexOrOption field of the QueryCell structure is a special query option value (indicated by a value greater than or equal to 0xF00000000), the query element represents a special option rather than a constraint. If this value is eSQO_OPTHINT (see section 2.2.1.3), this option is an optimization hint and MUST NOT affect the results of validation. Behavior of the server on receipt of special options other than eSQO_OPTHINT is undefined, because clients MUST NOT send these values, and they do not affect interoperability.<308>

      • If the IndexOrOption field of the QueryCell structure is an index of a property in the table (indicated by a value strictly less than 0xF00000000), the query element represents a constraint on the property. The server MUST verify that the value of this property in the entry write conforms to the constraint specified by the query element, and fail the call if not.

    • The server MUST make a preliminary selection of zero or one existing entries in the table for the entry write based on the primary key properties specified in the table's definition (as specified in section 3.1.1.3), as follows:

      • If there exists an existing entry in the table for which the values of each primary key property are equal to the values specified for the properties in the entry write, the server MUST preliminarily select that entry for the entry write (note that due to the primary key constraints on the table, it is guaranteed that there will be at most one such entry).

      • Otherwise, the server MUST preliminarily select no entry for that entry write.

  • The server then MUST verify that each existing entry was preliminarily selected for at most one entry write, and fail the call if not.

  • For each add, the server MUST perform the following:

    • The server MUST verify that no entry was preliminarily selected for the entry write, and fail the call if not.

    • For each primary key property and for each property constrained in the query (note that these sets of properties will possibly overlap), the server MUST perform the following:

      • The server MUST verify that the Changed bit (see section 2.2.1.8) is set in the Status field for the property in the entry write, and fail the call if not.

      • The server SHOULD<309> perform validation of constraints that are specified as a server validation requirement in the definition of the property and its type and fail the call if any constraint enforced by the server is violated.

  • For each update or remove, the server MUST perform the following:

    • The server MUST verify that an existing entry was preliminarily selected for the entry write, and fail the call if not. This entry is now said to be selected for the entry write.

    • For each primary key property and for each property constrained in the query (note that these sets of properties will possibly overlap), the server MUST perform the following:

      • The server MUST verify that the Changed bit (see section 2.2.1.8) is cleared in the Status field for the property in the entry write, and fail the call if not.

      • The server SHOULD<310> perform validation of constraints that are specified as a server validation requirement in the definition of the property and its type and fail the call if any constraint enforced by the server is violated.

The remainder of the protocol behavior specified for this method SHOULD be performed as an atomic transaction; that is, either the operation SHOULD fully succeed or the server SHOULD make no changes to the catalog. This described behavior is provided to facilitate the explanation of how the protocol behaves. This document does not mandate that implementations adhere to this model as long as their external behavior is consistent with that described in this document.

The server MUST attempt to perform each of the entry writes, specified as follows for each type of entry write, in an order arbitrarily selected by the server.

For each add, the server MUST perform the following:

  • The server MUST attempt to create a new entry in the table, and fail if it cannot.

  • For each property in the table, in a trigger-consistent order (see section 3.1.1.2.8) arbitrarily selected by the server, the server MUST then perform the following:

    • If the Changed bit (see section 2.2.1.8) is set in the Status field for the property in the entry write, the server MUST perform the following:

      • If the property is a read-only property (see section 3.1.1.2.8), the server SHOULD<311> fail the call. If the server does not fail the call, the server's behavior is undefined as this does not affect interoperability.

      • If the property is an internal property (see section 3.1.1.2.7), the server's behavior is undefined as this does not affect interoperability. In particular, the server MAY fail the call.

      • If the property is neither a read-only property nor an internal property, the server MUST attempt to set the value of the property in the newly created entry to the value specified in the entry write, and fail the call if it cannot.

      • If the server has a trigger (see section 3.1.1.2.8) for the property, the server MUST attempt to perform the trigger, and fail the call if it cannot.

    • If the Changed bit (see section 2.2.1.8) is cleared in the Status field for the property, the server MUST attempt to set the value of the property in the newly created entry to an implementation-specific default value (see section 3.1.1.2.6), and fail the call if it cannot.

  • The server MUST verify that the newly created entry conforms to the constraints specified in the table definition and any implementation-specific additional constraints (see section 3.1.1.2.5), and fail the call if not.

  • The server MUST verify that the newly created entry conforms to the add restrictions specified in the table definition, and fail the call if not.

  • If the table definition specifies an optional populate (see section 3.1.1.2.11), the server MAY<312> attempt to perform this populate as specified in the table definition. If the server attempts to perform a populate and is unable to do so, it SHOULD fail the call.

For each update, the server MUST perform the following:

  • The server MUST verify that the selected entry conforms to the update restrictions specified in the table definition, and fail the call if not.

  • For each property in the table, in a trigger-consistent order (see section 3.1.1.2.8) arbitrarily selected by the server, the server MUST then perform the following:

    • If the Changed bit (see section 2.2.1.8) is set in the Status field for the property in the entry write, the server MUST perform the following:

      • If the property is a read-only property (see section 3.1.1.2.8), the server SHOULD<313> fail the call. If the server does not fail the call, the server's behavior is undefined as this does not affect interoperability.

      • If the property is an internal property (see section 3.1.1.2.7), the server's behavior is undefined, because this does not affect interoperability. In particular, the server MAY fail the call.

      • If the property is neither a read-only property nor an internal property, the server MUST attempt to set the value of the property in the entry prototype to the value specified in the entry write, and fail the call if it cannot.

      • If the server has a trigger (see section 3.1.1.2.8) for the property, the server MUST attempt to perform the trigger, and fail the call if it cannot.

  • The server MUST verify that the entry represented by the Entry field of the TableEntryFixedWrite structure and the TableEntryVariable structure conforms to the query specified in pQueryCellArray, cbQueryCellArray, pQueryComparison, and cbQueryComparison.

  • The server MUST verify that there currently exists in the table an entry for which the values of the primary key properties, as specified in the table's definition (as specified in section 3.1.1.3), are equal to the values specified for these properties in the write entry.

  • The server MUST verify that the existing entry allows updates, according to properties of the entry and possibly properties of entries in other tables, as specified in the table's definition (as specified in section 3.1.1.3).

  • The server then MUST make changes to the entry as follows:

    • Each property for which the Changed bit (see section 2.2.1.8) is set in the corresponding Status subfield in the Entry field of the TableEntryFixedWrite structure is said to be marked for update. For each property marked for update, the server MUST perform the following:

      • The server SHOULD<314> verify that the property supports updates, as specified in the table's definition, as specified in section 3.1.1.3.

      • The server MUST attempt to set the value of the property in the entry to the value specified in the write, and fail the call if it cannot.

      • If an add/update trigger is specified for the property in the table's definition, as specified in section 3.1.1.3, the server MUST attempt to modify the entry as specified for that trigger, based on the value of the property, and fail the call if it cannot.

    • The server MUST verify that the modified entry conforms to the constraints specified for the table in its definition, as specified in section 3.1.1.3.

For each remove, the server MUST perform the following:

  • The server MUST verify that the selected entry conforms to the remove restrictions specified in the table definition, and fail the call if not.

  • The server MUST attempt to remove the selected entry from the table and fail the call if it cannot.

  • If a cascade (see section 3.1.1.2.10) is specified for the table in its definition, as specified in section 3.1.1.3, the server MUST attempt to perform the cascade, and fail the call if not.

The server MUST then set the values referenced by the out parameters as follows:

  • If the server generated any TableDetailedError (section 2.2.1.16) records, it MUST set the values referenced by ppTableDetailedErrors and pcbDetailedErrors to the constructed TableDetailedErrorArray (section 2.2.1.17) structure. Otherwise, it MUST set the value referenced by ppTableDetailedErrors to NULL and the value referenced by pcbDetailedErrors to zero.

Upon success, before returning from the call, the server SHOULD guarantee that the changes will be written to its data store. However, the server MAY<315> actually write changes to the data store asynchronously after returning. For example, a server might write changes to a temporary store and integrate these changes with its main data store asynchronously. In this case, it is possible for the changes not to be visible to the client immediately. For more details about synchronization, see section 3.1.4.17.2.

Upon success, the server MUST return S_OK (0x00000000). Upon failure in which detailed error results are returned, the server MUST return E_DETAILEDERRORS (0x80110802).