4.2 Reading a Table

Reading a table

Figure 7: Reading a table

The preceding figure shows the sequence for a COMA client (which has already initialized a session with the COMA server) trying to read the Partitions table (section 3.1.1.3.7) from a COMA server on behalf of a client application that requested this information. During this phase, it has already determined that the COMA server supports multiple partitions.

  • The COMA client calls IClientTableInfo::GetClientTableInfo to determine the metadata for the table. Before making the call, the client performs the following steps:

    • The client passes in the catalog identifier for the COMA catalog (section 1.9).

    • The client determines the GUID for the table that it wants to query. In this case, it is the Partitions table.

    • The client then determines the appropriate query to pass in order to retrieve all rows in the Partitions table.

    • The client ensures that it passes in eQUERYFORMAT_1 for the eQueryFormat parameter.

     HRESULT
     IClientTableInfo::GetClientTableInfo(
         [in] GUID* pCatalogIdentifier = {
                 6e38d3c4-c2a7-11d1-8dec-00c04fc2e0c7},
         [in] GUID* pTableIdentifier = {
                 e4ad9fd6-d435-4cf5-95ad-20ad9ac6b59f},
         [in] DWORD tableFlags = 0x00000000,
         [in, size_is(cbQueryCellArray), unique] 
                 char* pQueryCellArray = NULL,
         [in] ULONG cbQueryCellArray = 0x00000000,
         [in, size_is(cbQueryComparison), unique]
                 char* pQueryComparison = NULL,
         [in] ULONG cbQueryComparison = 0x00000000,
         [in] DWORD eQueryFormat = 0x00000001,
         [out] GUID* pRequiredFixedGuid =
                 {pointer to uninitialized memory for the GUID},
         [out, size_is( , *pcbReserved1)] char** ppReserved1 = 
                 {pointer to uninitialized memory},
         [out] ULONG* pcbReserved1 = 
                 {pointer to uninitialized memory},
         [out, size_is( , *pcAuxiliaryGuid)] GUID** ppAuxiliaryGuid = 
                 {pointer to uninitialized memory
                  to receive a pointer to an array of GUIDs},
         [out] ULONG* pcAuxiliaryGuid = 
                 {pointer to uninitialized memory to receive
                  the count of number of elements in ppAuxiliaryGuid},
         [out, size_is( , *pcProperties)]
                 PropertyMeta** ppPropertyMeta =
                 {pointer to uninitialized memory to receive
                  a pointer to an array of PropertyMeta},
         [out] ULONG* pcProperties =
                 {pointer to uninitialized memory to 
                  receive a count of elements in ppPropertyMeta},
         [out] IID* piid =
                 {pointer to uninitialized memory to receive 
                  the IID of the interface returned by pItf}, 
         [out, iid_is(o_piid)] void** pItf = 
                 {pointer to the memory to receive
                  the interface to read the table},
         [out, size_is( , *pcbReserved)] char** ppReserved2 =
                 {pointer to uninitialized memory},
         [out] ULONG* pcbReserved2 = 
                 {pointer to uninitialized memory});
      
    
  • The server performs the following verification steps:

    • The server verifies that the arguments conform to the syntax specified in section 3.1.4.7.1.

    • The server then verifies that pTableIdentifier matches the tables it supports. In this case, it is the table identifier for the Partitions table.

    • The server further verifies that the passed-in value for tableFlags is supported for the Partitions table.

    • It then verifies that the queries specified by pQueryCellArray and pQueryComparision array are indeed supported for the Partitions table.

  • After verification, the server performs the following steps:

    • The server determines that no auxiliary GUID needs to be passed back to the client for this table, so it zeros out the ppAuxiliaryGuid and pcAuxiliaryGuid parameters.

    • The server then determines the metadata for the Partitions table and populates pcProperties and ppProperties. The following is the tabular listing of the data filled into the array.

       DataType

       cbSize

       Flags

      eDT_GUID

      0x10

      fPROPERTY_PRIMARYKEY |

      fPROPERTY_NOTNULLABLE

      eDT_LPWSTR

      Variable size

      fPROPERTY_NOTNULLABLE

      eDT_LPWSTR

      Variable size

      No constraints.

      eDT_LPWSTR

      4

      fPROPERTY_FIXEDLENGTH |

      fPROPERTY_NOTNULLABLE

      eDT_LPWSTR

      4

      fPROPERTY_FIXEDLENGTH |

      fPROPERTY_NOTNULLABLE

    • The server finally sets pItf to the interface pointer to the object implementing ICatalogTableRead for the client to use for reading the table.

  • The server then returns S_OK.

     HRESULT = S_OK
     IClientTableInfo::GetClientTableInfo(
         [in] GUID* pCatalogIdentifier = {unchanged},
         [in] GUID* pTableIdentifier = {unchanged},
         [in] DWORD tableFlags = {unchanged},
         [in, size_is(cbQueryCellArray), unique]
                 char* pQueryCellArray = {unchanged},
         [in] ULONG cbQueryCellArray = {unchanged},
         [in, size_is(cbQueryComparison), unique] 
                 char* pQueryComparison = {unchanged},
         [in] ULONG cbQueryComparison = {unchanged},
         [in] DWORD eQueryFormat = {unchanged},
         [out] GUID* pRequiredFixedGuid = 
                 {92AD68AB-17E0-11D1-B230-00C04FB9473F},
         [out, size_is( , *pcbReserved1)] 
                 char** ppReserved1 = NULL,
         [out] ULONG* pcbReserved1 = 0x00000000,
         [out, size_is( , *pcAuxiliaryGuid)] 
                 GUID** ppAuxiliaryGuid = NULL,
         [out] ULONG* pcAuxiliaryGuid = 0x00000000,
         [out, size_is( , *pcProperties)]
                 PropertyMeta** ppPropertyMeta = 
                 {an array of PropertyMeta, see above for details},
         [out] ULONG* pcProperties = 0x00000005,
         [out] IID* piid = {0e3d6630-b46b-11d1-9d2d-006008b0e5ca}, 
         [out, iid_is(o_piid)] void** pItf = 
                 {ICatalogTableRead interface pointer},
         [out, size_is( , *pcbReserved)] char** ppReserved2 = NULL,
         [out] ULONG* pcbReserved2 = 0x00000000);
      
    
  • The COMA client remembers the column metadata passed back to it through an array of PropertyMeta.

  • The client then calls ICatalogTableRead::ReadTable (section 3.1.4.8.1) using the interface pointer that it received previously through IClientTableInfo::GetClientTableInfo, using a query for the Partitions table to get all rows appropriately, such that the query is one of the queries allowed for the Partitions table.

     HRESULT
     ICatalogTableRead::ReadTable(  
         [in] GUID* pCatalogIdentifier = 
                 {6e38d3c4-c2a7-11d1-8dec-00c04fc2e0c7},
         [in] GUID* pTableIdentifier = 
                 {e4ad9fd6-d435-4cf5-95ad-20ad9ac6b59f},
         [in] DWORD tableFlags = 0x00000000,  
         [in, size_is(cbQueryCellArray), unique]
                 char* pQueryCellArray = NULL,  
         [in] ULONG cbQueryCellArray = 0x0000000,  
         [in, size_is(cbQueryComparison), unique]
                 char* pQueryComparison = NULL,  
         [in] ULONG cbQueryComparison = 0x00000000,
         [in] DWORD eQueryFormat = 0x00000001,  
         [out, size_is( , *pcbTableDataFixed)]
                 char** ppTableDataFixed = {pointer to 
                  uninitialized memory for fixed size table data},
         [out] ULONG* pcbTableDataFixed = {pointer to uninitialized
                 memory for size of fixed size table data},
         [out, size_is( , *pcbTableDataVariable)]
                 char** ppTableDataVariable = {pointer to 
                  uninitialized memory for variable size table data},
         [out] ULONG* pcbTableDataVariable = {pointer to uninitialized
                 memory for size of variable size table data},
         [out, size_is( , *pcbTableDetailedErrors)]
                 char** ppTableDetailedErrors = {pointer to 
                  uninitialized memory for detailed query errors},
         [out] ULONG* pcbTableDetailedErrors = 
                 {pointer to uninitialized memory for size
                  of detailed query errors},
         [out, size_is( , *pcbReserved1)] char** ppReserved1 = 
                 {pointer to uninitialized memory},
         [out] ULONG* pcbReserved1 = 
                 {pointer to uninitialized memory},
         [out, size_is( , *pcbReserved2)] char** ppReserved2 = 
                 {pointer to uninitialized memory},
         [out] ULONG* pcbReserved2 =
                 {pointer to uninitialized memory});
      
    
  • The server receives the call and verifies that all the parameters are correct. For details, see the previous example.

  • The server then proceeds to process the query. If no error occurs during processing, then the query used in this example gets all the rows from the Partitions table. In this case, these rows in tabular form are the following.

     PartitionIdentifier

     Name

     Description

     Changeable

     Deleteable

    {41e90f3e-56c1-4633-81c3-6e8bac8bdd70}

    "Base Application Partition"

    ""

    "Y"

    "N"

  • The server then marshals the values appropriately, as specified by their metadata description agreed upon with the client through a previous call to IClientTableInfo::GetClientTableInfo.

  • After successfully marshaling the data into ppTableDataFixed and ppTableDataVariable, the server returns S_OK.

     HRESULT = S_OK
     ICatalogTableRead::ReadTable(  
         [in] GUID* pCatalogIdentifier = {unchanged},
         [in] GUID* pTableIdentifier = {unchanged},
         [in] DWORD tableFlags = {unchanged},
         [in, size_is(cbQueryCellArray), unique]
                 char* pQueryCellArray = {unchanged},  
         [in] ULONG cbQueryCellArray = {unchanged},  
         [in, size_is(cbQueryComparison), unique] char* 
                 pQueryComparison = {unchanged},  
         [in] ULONG cbQueryComparison = {unchanged},  
         [in] DWORD eQueryFormat = {unchanged},  
         [out, size_is( , *pcbTableDataFixed)]
                 char** ppTableDataFixed = 
                  {pointer to fixed size data of the partition table},  
         [out] ULONG* pcbTableDataFixed = 0x00000028,  
         [out, size_is( , *pcbTableDataVariable)] 
                 char** ppTableDataVariable = {pointer to variable
                  size data of the partition table},  
         [out] ULONG* pcbTableDataVariable = 0x0000003c,  
         [out, size_is( , *pcbTableDetailedErrors)]
                 char** ppTableDetailedErrors = NULL,  
         [out] ULONG* pcbTableDetailedErrors = 0x00000000,  
         [out, size_is( , *pcbReserved1)] char** ppReserved1 = NULL,  
         [out] ULONG* pcbReserved1 = 0x00000000,  
         [out, size_is( , *pcbReserved2)] char** ppReserved2 = NULL,  
         [out] ULONG* pcbReserved2 = 0x00000000);
      
    
  • The client on return of the call processes the ppTableDataFixed and ppTableDataVariable buffers.

  • The following is the layout of the ppTableDataFixed buffer received by the client.


    0


    1


    2


    3


    4


    5


    6


    7


    8


    9

    1
    0


    1


    2


    3


    4


    5


    6


    7


    8


    9

    2
    0


    1


    2


    3


    4


    5


    6


    7


    8


    9

    3
    0


    1

    0

    0

    0

    0

    0

    0

    1

    1

    0

    0

    0

    0

    0

    0

    1

    1

    0

    0

    0

    0

    0

    0

    1

    1

    0

    0

    0

    0

    0

    0

    1

    1

    0

    0

    0

    0

    0

    0

    1

    1

    Padding

    0x41E90F3E

    0x463356C1

    0x8B6EC381

    0x70DD8BAC

    0x00000000

    0x00000038

    0x00000059

    0x0000004E

    • The first 5 bytes represent the status bit field for each field. The client determined the type and count of these fields from the previous call to IClientTableInfo::GetClientTableInfo.

    • The client uses the first 5 bytes to parse through each fStatusProperty bit field (section 2.2.1.8) for each property. These map out to the following.

       Property

       Status Value

       Meaning

      PartitionIdentifier

      0

      0

      0

      0

      0

      0

      1

      1

      Changed/Non-null

      Name

      0

      0

      0

      0

      0

      0

      1

      1

      Changed/Non-null

      Description

      0

      0

      0

      0

      0

      0

      1

      1

      Changed/Non-null

      Deleteable

      0

      0

      0

      0

      0

      0

      1

      1

      Changed/Non-null

      Changeable

      0

      0

      0

      0

      0

      0

      1

      1

      Changed/Non-null

    • Because the table does not contain any variable-size properties that require size specification, no size information follows the status bit fields.

    • Because the client has detected the metadata for the Partitions table properties, it determines that the ppTableFixedSize buffer does not contain any size specifications for any properties. Therefore, the client interprets the rest of the data as defined by the following table.

       TableFieldName

       Value

       Offset

      PartitionIdentifier

      {41e90f3e-56c1-4633-81c3-6e8bac8bdd70}

      -

      Name

      -

      0x00

      Description

      -

      0x38

      Deleteable

      "Y"

      -

      Changeable

      "N"

      -

    • The client now has enough information to extract name and description properties from the ppTableVariableSize buffer.

      00

      01

      02

      03

      04

      05

      06

      07

      08

      09

      0a

      0b

      0c

      0d

      0e

      0f

      00

      B

      a

      s

      e

      A

      p

      p

      10

      L

      i

      c

      a

      t

      i

      o

      n

      20

      P

      a

      r

      t

      i

      t

      i

      30

      O

      n

      \0

      \0

      \0

    • The COMA client extracts the Name property by scanning from its offset (0x00) until it reaches the terminating null character at offset 0x34, reading the string "Base Application Partition".

    • The COMA client extracts the Description property by scanning from its offset (0x38) until it reaches the terminating null character, which it finds immediately at offset 0x38. It reads an empty string, "".

    • This completes the client query of the table.