Report Data Retrieval Logic Block
The data retrieval code block is used to populate temp-tables with data. A dynamic query must be used if there are any search fields, since the search conditions come from the client request and can vary at run time based on the user’s selections on the prompt page of the report viewer. The data retrieving logic should be coded into the designated place in the data source program.
Defining the Dynamic Query
Here is an example that illustrates how to structure the code for the dynamic query. Note that the search fields all reside in the so_mstr table.
define variable queryString as character no-undo.
define variable hSOQuery as handle.
define query SOQuery for so_mstr.
hSOQuery = query SOQuery:handle.
queryString = "for each so_mstr no-lock "
+ " where so_mstr.so_domain = " + QUOTER(global_domain).
run FillQueryStringVariable in reportHandle (input "ttSalesHeader", input "so_nbr", input-output queryString).
run FillQueryStringVariable in reportHandle (input "ttSalesHeader", input "so_cust", input-output queryString).
run FillQueryStringVariable in reportHandle (input "ttSalesHeader", input "order_date", input-output queryString).
queryString = queryString + ":".
hSOQuery:query-prepare(queryString).
hSOQuery:query-open().
hSOQuery:get-next().
Note: The FillQueryStringVariable function will get the search conditions sent from the client request (each consisting of the search field, operator, and value entered by the user) and then construct the corresponding where clause fragment and add it to the query string dynamically at run time.
The following lists the input parameters for the FillQueryStringVariable function:
|
Name
|
Input/Output
|
Data Type
|
Description
|
|
bufferName
|
Input
|
Character
|
Temp-table name
|
|
fieldName
|
Input
|
Character
|
Field name in the temp-table
|
|
queryString
|
Input-Output
|
Character
|
Dynamic query string
|
Note: For the function to work, the temp-table fields defined as search fields in the metadata definition should use exactly the same names as those in the database.
Note: If other static filter conditions are desired in the query string, they can be added in place of the “where true” part of the query string in the above example. For example, if we wanted this report to filter its query to only include orders whose so_site value is “SITE1”, we could use the following statement to begin the query string:
queryString = "for each so_mstr no-lock where so_site = " + QUOTER("SITE1").
The QUOTER() function returns the input string wrapped in quotes, and is useful when specifying text in a dynamic query string that must appear quoted in the final query string.
If static sorting is desired, a “by” clause can be added at the end of the dynamic query string. For example, the following change to our above example will cause records to be sorted primarily by so_cust:
queryString = queryString + " by so_cust:".
There is another procedure called FillQueryString that will automatically add the filter conditions for all the fields in a given temp-table. This is often the most concise way to implement filter fields. The following code statement illustrates how to use this procedure:
run FillQueryString in reportHandle (input "ttSalesHeader", input-output queryString).
The following lists the input parameters for the FillQueryString function:
|
Name
|
Input/Output
|
Data Type
|
Description
|
|
bufferName
|
Input
|
Character
|
Temp-table name
|
|
queryString
|
Input-Output
|
Character
|
Dynamic query string
|
Retrieving Data
Loop over the so_mstr records to create the ttSalesHeader temp-table and retrieve detailed information from each record. The inner loop over so_det records is used to retrieve all detail records for each master record.
repeat while not hSOQuery:query-off-end:
create ttSalesHeader.
assign
ttSalesHeader.so_nbr = so_mstr.so_nbr
ttSalesHeader.so_cust = so_mstr.so_cust
ttSalesHeader.so_ord_date = so_mstr.so_ord_date
ttSalesHeader.sales_order_slspsn1 = so_mstr.so_slspsn[1]
ttSalesHeader.sales_order_slspsn2 = so_mstr.so_slspsn[2]
ttSalesHeader.sales_order_slspsn3 = so_mstr.so_slspsn[3].
ttSalesHeader.sales_order_slspsn4 = so_mstr.so_slspsn[4].
for each sod_det no-lock
where sod_det.sod_nbr = so_mstr.so_nbr:
create ttSoLine.
assign
ttSoLine.sales_order_number = sod_det.sod_nbr
ttSoLine.sales_detail_line = sod_det.sod_line
ttSoLine.sales_detail_item = sod_det.sod_part
ttSoLine.sales_detail_unit_measure = sod_det.sod_um
ttSoLine.sales_detail_due_date = sod_det.sod_due_date.
end.
hSOQuery:get-next().
end. /* Repeat query */
Dynamic Report Settings by Data Source Program
Starting with the QAD .NET UI 2013 EE release, you can have your data source program dynamically set report settings. This approach allows most report settings to be set by the data source, including the layout.
Important: This is an improved and generalized mechanism that supercedes the dynamic layout selection by data source mechanism (see
Dynamic Layout Selection by Data Source). This improved mechanism not only allows the data source program to determine the layout (sys_default_report_definition setting) but also can be used to determine other report settings as well. The previous technique that was specific to choosing the report layout is still supported for back compatibility; however, a data source program cannot use both techniques in the same program.
Here are the steps to follow to enable your data source program to set report settings:
1 Add a special table called DataSourceReportSettings to your data set, with the following exact definition:
define temp-table DataSourceReportSettings
field setting_name as character
field setting_value as character
.
You should add it to the data set definition without relations (as in the following example, where the business tables ttSalesHeader and ttSoLine are related, but DataSourceReportSettings is not):
define dataset dsReportResults for ttSalesHeader, ttSoLine, DataSourceReportSettings
data-relation drLine for ttSalesHeader, ttSoLine
relation-fields (so_nbr, sales_order_number)
.
2 Populate the DataSourceReportSettings table with one row per setting in the RunReport procedure. The following example illustrates this, showing how to change various language, date, and number format settings:
/* Set setting for label language */
create DataSourceReportSettings.
assign
DataSourceReportSettings.setting_name = "sys_mfg_language"
DataSourceReportSettings.setting_value = "GE"
.
/* Set setting for ISO language, used for number-to-word translations and other settings */
create DataSourceReportSettings.
assign
DataSourceReportSettings.setting_name = "sys_language"
DataSourceReportSettings.setting_value = "de"
.
/* Set setting for numbers' decimal digits*/
create DataSourceReportSettings.
assign
DataSourceReportSettings.setting_name = "sys_ci_decimal_digits"
DataSourceReportSettings.setting_value = "3"
.
/* Set setting for numbers' decimal symbol */
create DataSourceReportSettings.
assign
DataSourceReportSettings.setting_name = "sys_ci_decimal_separator"
DataSourceReportSettings.setting_value = ","
.
/* Set setting for numbers' thousands separator */
create DataSourceReportSettings.
assign
DataSourceReportSettings.setting_name = "sys_ci_group_separator"
DataSourceReportSettings.setting_value = "."
.
/* Set setting for date format */
create DataSourceReportSettings.
assign
DataSourceReportSettings.setting_name = "sys_ci_short_date_pattern"
DataSourceReportSettings.setting_value = "yyyy.M.d"
.
/* Set setting for search criteria location (3 = None, to not show it in the report output) */
create DataSourceReportSettings.
assign
DataSourceReportSettings.setting_name = "sys_search_criteria_display"
DataSourceReportSettings.setting_value = "3"
.
3 (Optional) Add metadata to expose the setting value to be viewed by the user in the report output, or appear as search field on the prompt page. This is done in your FillMetaData procedure, the same way in which any field metadata is specified. Make sure that the buffer name is set to DataSourceReportSettings; any field name can be used. The field can optionally be marked as a search field (by setting its isSearchField metadata attribute to true), in which case users can enter their choice of values for that report setting. To retrieve the user’s value entered on the search panel, use the GetFilterValue() function in your RunReport procedure, and then set the value as described in step 2.
Note: Some report settings can be changed by the user using the Settings button in the Report Viewer (including date and number settings, as well as language). If the data source program sets any of these settings, they will take precedence over any user-entered settings.
Dynamic Layout Selection by Data Source
It is possible for the data source program to dynamically determine which page layout to use for reports where more than one layout has been developed using the Report Resource Designer.
Important: This technique has been superceded by the more general technique that allows many report settings (including the layout) to be determined by the data source (see
Dynamic Report Settings by Data Source Program). The layout-specific technique described below is still supported for back compatibility; however, a data source program cannot use both techniques in the same program.
If a report has more than one page layout design created for it (each giving different visualizations of the same data), you can have the data source program logic select a particular layout at run-time. For example, if a report needed to output one type of form for data where a customer is in Germany and another output form if the customer is in Brazil, then the data source logic could choose the proper form layout automatically.
In the normal case where the data source program does not attempt to control the layout selection, the list of available layouts (displayed when the user clicks the Layouts tool button in the report viewer) is still available for users to choose before running the report. However, when the data source program asserts control over the layout, the Layouts tool button is disabled to prevent users from overriding the layout selection. It is also possible for the data source logic to allow the user to choose any desired subset of the layouts, if a manual override is deemed allowable, by displaying those options as a search field with a list of allowed layouts.
To specify dynamically selected layouts
1 Create multiple layouts in the Report Resource Designer, all for the same report code (RRO code).
2 To have your data source program choose the layout, include a table in your business data set called DataSourceReportSettings, with a char field called sys_default_report_definition.
3 Put the choice of layout name into this field and the QAD .NET UI client will use this for rendering. The layout name is the value entered in the Report Definition Name field when saving the definition from the Report Resource Designer (stored in rptresd_det.rptresd_name after being saved).
4 Specify metadata for the DataSourceReportSettings.sys_default_report_definition field. This causes the report viewer program to disable the Layouts tool button (which normally would be active and confusing due to the existence of multiple layouts).
You have a choice of whether to make this field searchable. If you want to give the user no contol over the layout, make this field non-searchable. If you want to allow the user some control over which layout to use, make it searchable. You can provide a value list for this field in the metadata, which controls the list of layouts that the user can choose from in the search panel. If you make this searchable, you should get the user-entered value from the filter conditions and use it when populating the DataSourceReportSettings.sys_default_report_definition field in the code (described in step 2).
Note: When running this report from the menu, the above logic applies. However, when running the report from Report Resource Designer|Preview, the layout used is always whatever layout is currently in memory in the designer; the data source’s choice is always ignored. The designer’s approach is that the preview should always run what is in memory, which might not have been saved to the database yet. Consequently, to test the data source logic, it is necessary to run from the menu (perhaps requiring a temporary test menu item if the real menu item does not exist in the test system yet).