Data Mappings
This section describes how those data types that can be represented within a COM VARIANT structure are mapped to and from the OpenROAD 4GL data types. Mappings are of the following types:
• Scalar
• Pseudo-scalar
• Structured
• Special
Scalar Type Mappings
A limited number of scalar VARIANT data types are supported. The types of the values supplied as input must be compatible with the OpenROAD data type of the corresponding parameter (or user class attribute) in the 4GL procedure. The following table describes these compatible mappings:
For the purposes of data mapping, the OpenROAD StringObject, LongByteObject, and BitmapObject types are considered to be scalar types, as is the VARIANT “one-dimensional array of VT_UI1.”
On output, the OpenROAD types are mapped back into VARIANT data types, as described in the following table:
Note: VARCHAR data is character data, not binary, and is converted to UNICODE for the VT_BSTR. LongByteObject data is binary data, and treated as an uninterpreted stream of bytes.
With ByRef parameters, it is possible that some VARIANT values may go in as one data type and come back as a slightly different (compatible) data type. This is not an issue for programmers using the OpenROAD 4GL RemoteServer system class interface, but programmers using other languages should be aware of the possibility. For example, a VT_R8 could be mapped to a 4GL DECIMAL on input, but when it is output, the 4GL DECIMAL is converted to a VT_DECIMAL. The Parameter Data Object hides this detail because the PDO automatically coerces all returned data back to the type with which it was declared in the PDO.
Pseudo-scalar Type Mappings
The StringObject, LongByteObject, and BitmapObject instances are treated as scalar values (and not entirely as objects) for the purposes of mapping to and from COM VARIANTs. The VARIANT representation of these OpenROAD objects contains only the raw text or binary data associated with that object. It is not a full encoding of the attributes of the object.
When a VT_BSTR value is mapped to an attribute of type StringObject in the OpenROAD Server, a default instance of a StringObject is created and its text value is set to match the VT_BSTR string that was sent in. When a StringObject attribute is sent back with ByRef, the text value is extracted and converted back to a VT_BSTR string. All other attributes of the StringObject (such as FileHandle or DBHandle) are ignored on both input and output. This allows non-OpenROAD clients to easily map long character strings to OpenROAD StringObjects without having to construct a complex encoding.
When a “one-dimensional array of VT_UI1” value is mapped to an attribute of type LongByteObject in the OpenROAD Server, a default instance of a LongByteObject is created and the data value is set to the byte stream that was sent in. When a LongByteObject attribute is sent back with ByRef, the data value is extracted and converted back to a one-dimensional array of VT_UI1. All other attributes of the LongByteObject (such as FileHandle or DBHandle) are ignored on both input and output.
The mapping to and from BitmapObject is indirect, using LongByteObject as an intermediate step. The one-dimensional array of VT_UI1 VARIANT type is only mapped directly to and from LongByteObject. If the target attribute is of type BitmapObject, the input is first mapped to a LongByteObject (described previously), and then a default instance of a BitmapObject is created and its LoadLong method is used to transfer the LongByteObject data into the BitmapObject. On output, a default instance of a LongByteObject is created, and its LoadValue method is used to transfer the data from the BitmapObject into the temporary LongByteObject from which it is converted to a one-dimensional array of VT_UI1 (described previously). The OpenROAD Server only accepts (or returns) the bitmap byte stream. None of the other attributes of the BitmapObject is involved.
Structured Type Mappings
The OpenROAD Server supports structured data in the form of an OpenROAD user class or user class array.
A single user class instance can be thought of as a two-dimensional array with exactly one row, and with columns corresponding to the attributes of the user class. An array of user class instances can be thought of as a two-dimensional array with zero or more rows, each with columns corresponding to the attributes of the user class. Any attribute of a user class can itself contain a user class instance or array of user class instances, and this nesting can continue to any number of levels. Such nested structures are represented in the COM automation types as nested two-dimensional arrays of VARIANTs.
At the topmost level, the data to be mapped to the parameters of the 4GL procedure is packaged into a two-dimensional array with one row. The correspondence between the columns of this data array and the named parameters of the 4GL procedure is defined by a parallel descriptor array. The parameter descriptor array structure is generated automatically by the PDO and the OpenROAD 4GL RemoteServer system class, so clients never need to deal with it directly.
Note: It is not necessary to map to all the parameters of the procedure. Only those contained in the descriptor/data array pair are mapped. All others receive default values. The same is true at all nested levels. Only those user class attribute names listed in the nested descriptor are mapped. All others receive their default values. Similarly, when data is returned through ByRef, only those parameters and attributes listed in the descriptor are marshaled back.
Special Type Mappings
Empty and NULL values are supported for both the scalar and structured mappings.
A VARIANT containing a VT_EMPTY value is accepted as a default input value and is mapped to the default initial value for the corresponding 4GL scalar, user class instance, or array instance. This is a convenient way to initialize ByRef data that is used for output only, and it minimizes the marshaling cost of sending the input.
A VARIANT containing a VT_NULL value is mapped to a NULL value in the corresponding OpenROAD 4GL scalar, user class instance, or array instance. This mapping fails if the 4GL attribute was declared as a non-nullable type. NULL 4GL values are mapped back to VT_NULL when returned using ByRef.
The OpenROAD DATE data type requires several special cases because it is really a combination of the following multiple types:
• Timestamp
• Date-without-time
• Interval
• Blank date
The COM automation DATE data type can only represent timestamps, so special exceptions are made for the other DATE values.
Timestamp
OpenROAD timestamps are converted directly to COM DATE values. These timestamps are always transmitted in Greenwich Mean Time (GMT) form. The client must handle any shifting to a local time zone for display purposes.
This time-zone-shifting behavior is the default behavior for OpenROAD 4GL clients. OpenROAD timestamps are stored internally in GMT but always shifted from the local time zone on display input and shifted to the local time zone for display output.
The COM ParameterData interface does not do any time zone shifting. It only handles timestamps in GMT form. Non-4GL client applications must implement their own time zone shifting if desired.
Date-without-time
OpenROAD date-without-time values are represented in COM DATE values as midnight (GMT) timestamps, but they are not the same as timestamps. Following are some properties of date-without-time values:
• They are not subject to time zone shifting when formatted for display.
• They are transmitted as a GMT timestamp, but with an extra flag to identify them as a date-without-time value.
• They are transparently converted back to a real OpenROAD date-without-time value in an OpenROAD 4GL client, but the COM ParameterData interface returns the value as a GMT midnight timestamp.
• Non-4GL clients must call a helper method (IsDateWithoutTime) to determine if the value represents a normal timestamp or whether it represents a date-without-time.
• Non-4GL clients must never perform zone shifting of date-without-time values.
Interval
OpenROAD DATE interval values are not supported by the OpenROAD Server marshaling protocol. You can use intervals internally within a server application, but interval values cannot be transmitted between client and server within SCP parameters. If you need to communicate intervals between a client and server, those values must be converted to some other type that can be marshaled (such as varchar).
Blank Date
The OpenROAD blank date value is not the same as the NULL value. There is no value in the COM DATE data type that represents this blank value. To communicate this extra value through a COM VARIANT, it must be represented outside of the range of the COM DATE data type, where an empty string is used.
In an OpenROAD 4GL client, this empty string value is automatically converted back to an OpenROAD blank date value. Non-4GL clients must either test for the empty string or call a helper method (IsBlankDate) to determine if the value represents a blank date.