Supporting user-defined data type fields
You can define fields whose data type is user-defined. These fields are treated as alpha fields in most cases, except when ReportWriter displays them. Every time ReportWriter needs to access a user-defined field, it calls RW_USAGE_METHOD, RW_GETVAL_METHOD, or RPS_DATA_METHOD as follows:
- RW_USAGE_METHOD is called when a structure with user-defined fields is accessed by ReportWriter, either when defining new structures/files from which to read or when opening a report with one of these structures. RW_USAGE_METHOD validates usage and determines the internal data type.
- RW_GETVAL_METHOD is called when the field is being read from a data file and determines the actual value ReportWriter will use when sorting, selecting, performing calculations on the field, and so forth.
- RPS_DATA_METHOD is called when ReportWriter needs to display the field. This subroutine formats the data as necessary.
You can register your own versions of these routines to provide the desired mechanisms for displaying and using user-defined data type fields. These routines are ideal for supporting data types that are not supported directly or for supporting alternate date storage formats. (See the RW_USAGE_METHOD Examples.)
|
|
If you use these routines to access data that is larger than the stored representation, ReportWriter will access the user-defined field only as a field to print. |
RW_USAGE_METHOD
subroutine RW_USAGE_METHOD
a_user_text ,a ;User text string associated with field (a80)
a_user_data ,a ;User data string associated with the field (a30)
a_type ,n ;Returned with the field's data type for
; internal use (d1)
; 0 No data type change.
; 1 Alphanumeric.
; 2 Decimal.
; 3 Implied-decimal.
; 4 Integer.
a_size ,n ;Returned with field length (d4)
a_precision ,n ;Returned with field's precision if internal
; type is implied-decimal (d2)
a_class ,n ;Returned with field's class and is one of
; the following values (d1)
; 0 Neither date nor time field.
; 1-6 Date field.
; 8-9 Time field.
;These values correspond to date and time storage
; formats listed in your Repository User’s Guide.
Discussion
During file processing, ReportWriter calls this routine once for all user type data fields. The a_user_data and a_user_text strings, a_size, a_precision, and a_class are those that have been defined in the Repository for the selected field.
By default, user-defined data type fields are treated as alpha fields. If you want ReportWriter to use a different data type internally when processing the field, you can modify the distributed version of this routine.
A_type, a_size, a_precision, and a_class tell ReportWriter how to treat the field internally when it is used in a calculation, selection, or conditional or when it is used for sorting or totaling. During report execution, ReportWriter calls RW_GETVAL_METHOD to convert the actual data in the user-defined field each time it is referenced.
If this routine modifies the data type, when the field is displayed in ReportWriter, its data type will be shown as the internal data type, preceded by a “U”. For example, if the field was defined in the repository as a “U4” and this routine specifies its internal type to be decimal with a size of 4, it will be shown as “UD4”.
This routine is always passed a type value of 0. The version of this subroutine linked with the ReportWriter in your original distribution returns the a_type value unchanged, meaning that the user-defined field will be treated as alpha. The default version of this subroutine also returns the a_size, a_precision, and a_class unchanged.
The following example supports a user-defined data type field for dates stored as MMDDYY(YY).
; Filename: usr.dbl
;
; Function: Defines user-overloadable subroutines for
; ReportWriter
;
subroutine rps_data_method
;
; Description: Formats user-defined data type fields
;
; Arguments:
;
a_source ,a ;Source field data (a99)
a_dest ,a ;RETURNED - Modified field data (a99)
a_use ,n ;ReportWriter's use of data (see Notes) (d1)
a_usrtxt ,a ;User text string associated with data (a80)
a_usrdata ,a ;User data string associated with data (a30)
a_format ,a ;Format string associated with field (a40)
;
; Notes:
; ReportWriter calls this routine every time a user-defined
; field is displayed. See the Repository User’s Guide for more
; information on user-defined fields.
;
; a_use: When a_use is 0, the item is being output (printer,
; screen, or file). When a_use is not 0, the item is
; being used to format an input window.
;
.include "WND:tools.def"
record
year2 ,a2 ;2-digit year
year4 ,a4 ;4-digit year
year ,a4 ;Temporary storage for date (year)
month ,a2 ;Temporary storage for date (month)
day ,a2 ;Temporary storage for date (day)
date ,a10 ;Temporary storage for date (entire)
r_date ,a10 ;Date returned from u_fmtdat
proc
if (a_use) ;Format only for output
xreturn
if ^passed(a_format) then
begin
case (a_format) of
begincase
"MM-DD-YY ":
call format1
"MM/DD/YYYY ":
call format2
endcase
else
a_dest = a_source ;Default behavior of rps_data_method
end
else
a_dest = a_source
xreturn
format1,
date = ^d(a_source(1:6)), "XXXXXX"
xcall u_fmtdat(3, r_date, ^d(date),,, D_LEFT, 0, '-')
if (r_date(3:1).ne.'-') then
a_dest = "0" + r_date
else
a_dest = r_date
return
format2,
date = ^d(a_source(1:8)), "XXXXXXXX"
xcall u_fmtdat(6, r_date, ^d(date),,, D_LEFT, 0, '/')
if (r_date(3:1).ne.'/') then
a_dest = "0" + r_date
else
a_dest = r_date
return
endsubroutine
subroutine rw_usage_method
;
; Description: Determines user-defined data type usage
;
; Arguments:
;
a_usrtxt ,a ;User text string associated with data (a80)
a_usrdata ,a ;User data string associated with data (a30)
a_type ,n ;RETURNED - field's data type for internal
; usage (d1) (see Notes)
a_size ,n ;RETURNED - field's length (d4)
a_precision ,n ;RETURNED - Precision if internal type is
; implied-decimal (d2)
a_class ,n ;RETURNED Field class (see Notes) (d1)
;
;Notes:
; ReportWriter calls this routine every time a user-defined
; field is selected in a report. See the Repository User’s Guide
; for more information on user-defined fields.
;
proc
upcase a_usrdata
case (a_usrdata) of
begincase
"MMDDYY ":
call usage1
"MMDDYYYY":
call usage2
endcase
else
nop ;Default behavior of rw_getval_method
xreturn
usage1,
a_type = 2 ;Decimal
a_size = 6
a_precision = 0
a_class = 1 ;YYMMDD
return
usage2,
a_type = 2 ;Decimal
a_size = 8
a_precision = 0
a_class = 2 ;YYYYMMDD
return
endsubroutine
subroutine rw_getval_method
;
;Description: Returns user-defined data type value
;
;Arguments:
;
a_source ,a ;Source field data (a99)
a_dest ,a ;RETURNED - Modified field data (a99)
a_usrtxt ,a ;User text string associated with data (a80)
a_usrdata ,a ;User data string associated with data (a30)
a_type ,n ;Internal data type for the field (d1)
a_size ,n ;Internal size of the field (d4)
a_precision ,n ;Internal precision of the field if
; implied-decimal (d2)
;Notes:
; ReportWriter calls this routine during report generation
; for each user-defined data type field in each data record.
;
; This routine converts actual file data for user-defined fields
; before ReportWriter uses them for calculating, selecting,
; sorting, totaling, or defining a conditional.
;
; The values for each parameter are those returned from the
; RW_USAGE_METHOD routine when the user-defined field was selected.
;
record
syn_date1 ,d6 ;YYMMDD - Synergy/DE date format #1
s_year1 ,d2 @syn_date1
s_month1 ,d2 @syn_date1 + 2
s_day1 ,d2 @syn_date1 + 4
record
syn_date2 ,d8 ;YYYYMMDD - Synergy/DE date format #2
s_year2 ,d4 @syn_date2
s_month2 ,d2 @syn_date2 + 4
s_day2 ,d2 @syn_date2 + 6
record
my_date1 ,d6 ;MMDDYY - User-defined date format #1
m_month1 ,d2 @my_date1
m_day1 ,d2 @my_date1 + 2
m_year1 ,d2 @my_date1 + 4
record
my_date2 ,d8 ;MMDDYYYY - User-defined date format #2
m_month2 ,d2 @my_date2
m_day2 ,d2 @my_date2 + 2
m_year2 ,d4 @my_date2 + 4
record
date_out ,d8 ;Output for final date returned from dyadd
date_in ,a10 ;Temporary storage for date transfer
proc
upcase a_usrdata
case (a_usrdata) of
begincase
"MMDDYY ":
call getval1
"MMDDYYYY":
call getval2
endcase
else
a_dest = a_source ;Default behavior of RW_GETVAL_METHOD
xreturn
getval1,
date_in = ^d(a_source(1,6)), "XXXXXX"
my_date1 = ^d(date_in)
s_year1 = m_year1 ;Transfer date information
s_month1 = m_month1
s_day1 = m_day1
a_dest = syn_date1, "XXXXXX"
return
getval2,
date_in = ^d(a_source(1,8)), "XXXXXXXX"
my_date2 = ^d(date_in)
s_year2 = m_year2 ;Transfer date information
s_month2 = m_month2
s_day2 = m_day2
a_dest = syn_date2, "XXXXXXXX"
return
endsubroutine
RW_GETVAL_METHOD
subroutine RW_GETVAL_METHOD
a_source ,a ;Source field data
a_dest ,a ;Returned with modified field data
a_user_text ,a ;User text string associated with field (a80)
a_user_data ,a ;User data string associated with field (a30)
a_type ,n ;Internal data type for field (d1)
a_size ,n ;Internal size of field (d4)
a_precision ,n ;Internal precision of field if internal type
; is implied-decimal (d2)
Discussion
During report generation, ReportWriter calls this routine once for each record for each user-defined data type field selected in the report. The a_user_data and a_user_text strings and a_type, a_size, and a_precision are values that were returned from the RW_USAGE_METHOD routine when the user-defined field was selected.
You can use this routine to convert the actual file data for user-defined fields before ReportWriter uses them in a calculation, selection, or conditional or for sorting or totaling. The data value is retrieved as an alpha field with the contents in user storage format. RW_USAGE_METHOD converts this value to an alpha field that contains the Synergy DBL storage format for the type to which you are converting.
Avoid explicit casting (using the ^D or ^A functions or alpha = decimal format) in creating the field’s new type, as you may lose the sign of a decimal field by performing these conversions. Instead, use a decimal field overlaid with an alpha field, as follows, to convert the field to alpha format implicitly.
record
decimal ,d28
dec_alpha ,a28 @decimal
|
|
ReportWriter does not support changing data size using these routines. In this situation, you should convert to a decimal or alpha field of the same size. The version of this subroutine linked with ReportWriter in your original distribution returns the original data, unmodified, in a_dest. |
Note the following restrictions:
- If a user-defined field is a key segment in the primary file, optimizations in selection criteria and sorting use the storage format defined in the file, instead of the value returned from RW_GETVAL_METHOD. If you want to perform selection criteria on a user-defined field that is a key segment in the primary file and use the values as returned from RW_GETVAL_METHOD, you must create a temporary field that has that field as its expression. If a user-defined field is a segment of the primary key of the primary file, the default report is sorted on the storage format in the file of the user-defined field. The same is true if you depend on ReportWriter optimizations for sorting. For this reason, we do not recommend using user-defined fields in key segments.
- If two user-defined fields are overlaid, RW_GETVAL_METHOD is called for both fields. If the first field (as defined in the Repository) is reordered by RW_GETVAL_METHOD, the second field will be affected.
- If a user-defined field is used as a segment in a foreign key, any relations on that field use the value as returned from RW_GETVAL_METHOD.
See the RW_USAGE_METHOD Examples.
RPS_DATA_METHOD
subroutine RPS_DATA_METHOD
a_source ,a ;Source field data (a99)
a_dest ,a ;Returned with modified field data (a99)
a_use ,n ;Indicates ReportWriter's use for the data (d1)
; 0 Output (screen, printer, or file).
; 1 Input window.
a_user_text ,a ;User text string associated with the field (a80)
a_user_data ,a ;User data string associated with the field (a30)
a_format ,a ;(optional) Format string associated with field (a40)
Discussion
ReportWriter calls RPS_DATA_METHOD every time a user-defined data type field is displayed. (However, this routine is not called when the user-defined data type field is used as a sort field.) RPS_DATA_METHOD converts the storage format created by RW_GETVAL_METHOD into the format you want ReportWriter to display. Note that a format must be provided when you select a user-defined data type to print, and it must have at least the number of characters you wish to display within the format.
If a_use contains a value of 0, a_source is a field being printed on a detail line or break line. If a_use is nonzero, a_source is the input in a question field or a selection criteria comparison value. The user text string, user data string, and format string can contain whatever data is required to process the field.
Date and time fields do not automatically use the ReportWriter (or Repository) formats to display dates and times; you must perform this conversion yourself. This display conversion can also be performed using UI Toolkit U_FMTDAT and U_FMTTIM subroutines.
Remember to access implied-decimal fields as such before formatting, using the ^D function:
^d(a_source, precision)
The version of this subroutine linked with the ReportWriter in your original distribution returns the original data, unmodified, in a_dest.
Examples
Here’s a sample RPS_DATA_METHOD subroutine that formats the specified user-defined data type field based on the specified format. Also see the RW_USAGE_METHOD Examples.
subroutine rps_data_method
;
; Description: This subroutine formats the given user-defined data
; type field based on a format string stored in the
; field's user text area. Otherwise, it uses
; the format string passed.
; Arguments:
;
a_srcdat ,a ;Input source data string
a_dstdat ,a ;Output result data string
a_use ,a ;Use for user-defined field
a_usrtxt ,a ;User text string associated with source field
a_dattyp ,a ;Data type string associated with source field
a_fmtstr ,a ;Optional format string
; This example assumes the size of a_dstdat is big enough to load the
; extra format characters. The destination size can be controlled by a
; dummy format string size.
record
ix ,d3
t_dec ,d18
t_date1 ,d8 @t_dec
t_date2 ,d6 @t_dec
proc
if (a_use) ;Only format for output
xreturn
upcase a_usrtxt
case a_usrtxt of
begincase
"USER DATE #1":
begin
t_date1 = %d(a_srcdat) ;Destination source length must be
case a_usrtxt(16:3) of ; enough
begincase
"--":
xcall s_bld(a_dstdat,,"%4d%a%2a%a%2a",
& t_date1(1:4), a_usrtxt(16:3),
& t_date1(5:2), a_usrtxt(16:3),
& t_date1(7:2))
"***":
xcall s_bld(a_dstdat,, "%a%4d%a%2a%a%2a%a",
& a_usrtxt(16:3), t_date1(1:4),
& a_usrtxt(16:3), t_date1(5:2),
& a_usrtxt(16:3), t_date1(7:2),
& a_usrtxt(16:3))
endcase
end
"USER DATE #2":
begin
t_date2 = %d(a_srcdat) ;Destination source length must be
case a_usrtxt(16:3) of ; enough
begincase
"--":
xcall s_bld(a_dstdat,,"%4d%a%2a%a%2a",
& t_date2(1:4), a_usrtxt(16:3),
& t_date2(5:2), a_usrtxt(16:3),
& t_date2(7:2))
"***":
xcall s_bld(a_dstdat,, "%a%4d%a%2a%a%2a%a",
& a_usrtxt(16:3), t_date2(1:4),
& a_usrtxt(16:3), t_date2(5:2),
& a_usrtxt(16:3), t_date2(7:2),
& a_usrtxt(16:3))
endcase
end
endcase
else
if (%passed(a_fmtstr)) then ;Can use format string to
if (%instr(1, a_fmtstr, "&") then ; control format operation
begin
clear ix
do ;For all blanks, replace with "*"
begin
incr ix
if (a_srcdat(ix:1).eq." ") then
a_dstdat(ix:1) = "*"
else
a_dstdat(ix:1) = a_srcdat(ix:1)
end
until (ix.eq.%len(a_srcdat))
end
else
a_dstdat = a_srcdat
else
a_dstdat = a_srcdat
xreturn
endsubroutine
