In a SAS data set, a variable (column) can have persisted formatting information. To use the default format, you create an instance of SASFORMAT, set the wType member to SASFMT_FORMAT, and set the remaining members to zero (0) or NULL, as appropriate. To override the default format values, you can specify a format length (width) and number of decimals (for numeric formats).
Note: For more information about using the default format, see Applying Default Formats to Input Operations.
The example data set has three columns: SALEDATE, QUANTITY, and PRICE. These are the same sample columns that were used in the topic Applying Default Formats to Input Operations. However, in this case, the objective is to return SALEDATE using MMDDYY8. formatting and to return PRICE using DOLLAR8.2. formatting. In addition, there may be a need for the application to do some calculations on the PRICE column, so the example also binds to that column as a numeric value. As a result, this example requires the following four bindings (even though there are only three columns):
The following code will create an array of DBBINDING structures.
DBBINDING rgBindings[4];// Creates four bindings. DBBINDEXT rgBindingExtensions[2]; // Two bindings have SASFORMAT rgFormatOverrides[2]; // formatting overrides. ULONG dwOffset; // Used to track the offset of a bound data point into an I/O buffer.
As each binding is created, the following struct will be used to lay out a status and a value part.
typedef struct { DWORD status; BYTE value[1]; } COLUMNDEF;
As a matter of good programming, all structures are initialized, too.
memset( rgBindings, 0, sizeof( rgBindings ) ); memset( rgBindingExtensions, 0, sizeof( rgBindingExtensions ) ); memset( rgFormatOverrides, 0, sizeof( rgFormatOverrides ) );
Parts are laid into the buffer at offset 0. When the bindings are created, dwOffset should be the total number of bytes needed to hold one row in memory.
dwOffset = 0;
SALEDATE is bound as DBTYPE_BSTR with the MMYYDD8. format applied. The basic OLE DB binding information comes first.
rgBindings[0].iOrdinal = 1; rgBindings[0].dwPart = DBPART_VALUE | DBPART_STATUS; rgBindings[0].obValue =dwOffset + offsetof( COLUMNDEF, value ); rgBindings[0].obStatus =dwOffset + offsetof( COLUMNDEF, status ); rgBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED; rgBindings[0].wType = DBTYPE_BSTR;
The format override is set up for this column.
rgFormatOverrides[0].wType = SASFMT_FORMAT; rgFormatOverrides[0].pwszName = L"MMYYDD"; rgFormatOverrides[0].iLength = 8;
The SASFORMAT struct is linked to the DBBINDING struct.
rgBindingExtensions[0].pExtension = (BYTE *) &(rgFormatOverrides[0]); rgBindingExtensions[0].ulExtension = 1; rgBindings[0].pBindExt = &(rgBindingExtensions[0]);
The offset is set to increase past the data points for this column.
dwOffset += sizeof(BSTR) + offsetof( COLUMNDATA, value );
QUANTITY is bound as DBTYPE_R8. This case is simple because only basic OLE DB binding information is needed.
rgBindings[1].iOrdinal = 2; rgBindings[1].dwPart = DBPART_VALUE | DBPART_STATUS; rgBindings[1].obValue =dwOffset + offsetof( COLUMNDEF, value ); rgBindings[1].obStatus =dwOffset + offsetof( COLUMNDEF, status ); rgBindings[1].wType = DBTYPE_R8;
dwOffset += sizeof(double) + offsetof( COLUMNDATA, value );
PRICE is bound as DBTYPE_BSTR with the DOLLAR8.2 format applied. This is similar to the first binding that was created.
rgBindings[2].iOrdinal = 3; rgBindings[2].dwPart = DBPART_VALUE | DBPART_STATUS; rgBindings[2].obValue =dwOffset + offsetof( COLUMNDEF, value ); rgBindings[2].obStatus =dwOffset + offsetof( COLUMNDEF, status ); rgBindings[2].dwMemOwner = DBMEMOWNER_CLIENTOWNED; rgBindings[2].wType = DBTYPE_BSTR; rgFormatOverrides[1].wType = SASFMT_FORMAT; rgFormatOverrides[1].pwszName = L"DOLLAR"; rgFormatOverrides[1].iLength = 8; rgFormatOverrides[1].iDecimals = 2; rgBindingExtensions[1].pExtension = (BYTE *) &(rgFormatOverrides[0]); rgBindingExtensions[1].ulExtension = 1; rgBindings[2].pBindExt = &(rgBindingExtensions[0]);
dwOffset += sizeof(BSTR) + offsetof( COLUMNDATA, value );
PRICE is bound as DBTYPE_R8 .
rgBindings[3].iOrdinal = 3; rgBindings[3].dwPart = DBPART_VALUE | DBPART_STATUS; rgBindings[3].obValue =dwOffset + offsetof( COLUMNDEF, value ); rgBindings[3].obStatus =dwOffset + offsetof( COLUMNDEF, status ); rgBindings[3].wType = DBTYPE_R8;
After executing the following code, dwOffset will be the number of bytes that the application will need to store a row of data when that row of data is retrieved using this binding information.
dwOffset += sizeof(double) + offsetof( COLUMNDATA, value );