4.2 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
91
0
1
2
3
4
5
6
7
8
92
0
1
2
3
4
5
6
7
8
93
0
10
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.