Вы находитесь на странице: 1из 51

PROGRAMMING STANDARDS

PROGRESS V7- OE10


QAD Enterprise Applications

Contents
1
2

Introduction ................................................................................................................................................ 5
Database design........................................................................................................................................... 6
2.1
Table (database file) ...................................................................................................................... 6
2.2

Fields ............................................................................................................................................. 6

2.3

Indexes .......................................................................................................................................... 7

2.4

Database & Field triggers ............................................................................................................. 8

2.5

Sequences...................................................................................................................................... 9

2.6

Customizing databases .................................................................................................................. 9

Naming conventions.................................................................................................................................. 11
3.1
General ........................................................................................................................................ 11
3.2

External procedures (programs) .................................................................................................. 11

3.3

Internal procedures...................................................................................................................... 12

3.4

Functions ..................................................................................................................................... 12

3.5

Variables ..................................................................................................................................... 12

3.6

Remaining Widgets (normally in character/GUI window programs) ......................................... 13

3.7

Frames ......................................................................................................................................... 14

3.8

Buffers......................................................................................................................................... 14

3.9

Temporary Tables and Work Files.............................................................................................. 14

3.10

Tables & Database ...................................................................................................................... 15

3.11

Fields ........................................................................................................................................... 15

3.12

Streams ........................................................................................................................................ 15

3.13

Block labels................................................................................................................................. 16

3.14

Indexes ........................................................................................................................................ 16

3.15

Prodataset .................................................................................................................................... 16

3.16

Labels and Messages.................................................................................................................. 16

3.17

External References .................................................................................................................... 17

3.18

Browses ....................................................................................................................................... 17

3.19

Reporting framework .................................................................................................................. 17

Include files ............................................................................................................................................... 18


4.1
General ........................................................................................................................................ 18
4.2

QAD EA include files ................................................................................................................. 18

Procedure structure .................................................................................................................................. 26


5.1
Header ......................................................................................................................................... 26
5.2

Variables ..................................................................................................................................... 26

5.3

Hard coded values / Pre-processors ............................................................................................ 27

Page |2

5.4

Other DEFINES .......................................................................................................................... 28

5.5

Forms & Define Frame ............................................................................................................... 29

5.6

Change an existing program ....................................................................................................... 29

Procedure style .......................................................................................................................................... 31


6.1
Indentation .................................................................................................................................. 31
6.2

Statements per line ...................................................................................................................... 31

6.3

Capitalisation .............................................................................................................................. 31

6.4

Block Labels ............................................................................................................................... 31

6.5

Punctuation ................................................................................................................................. 32

6.6

Comments ................................................................................................................................... 32

6.7

Use of Dictionary Formats/Labels .............................................................................................. 32

6.8

IF/THEN/ELSE & CASE ........................................................................................................... 32

6.9

Listing Field Names .................................................................................................................... 34

6.10

Keywords to be Aware of ........................................................................................................... 35

6.11

Abbreviations .............................................................................................................................. 35

6.12

Frames ......................................................................................................................................... 35

6.13

Transaction.................................................................................................................................. 36

6.14

Error Handling ............................................................................................................................ 36

6.15

Record Reading ........................................................................................................................... 36

6.16

Record Locking ........................................................................................................................... 39

6.17

Use of Progress/OE functions ..................................................................................................... 39

6.18

Combine statements .................................................................................................................... 40

6.19

Debugging ................................................................................................................................... 40

6.20

Miscellaneous ............................................................................................................................. 40

Portability .................................................................................................................................................. 42
7.1
Terminals .................................................................................................................................... 42
7.2

Workfiles..................................................................................................................................... 42

7.3

O.S. commands ........................................................................................................................... 42

Oracle issues .............................................................................................................................................. 44


8.1
Record creation and availability ................................................................................................. 44
8.2

Length of database fields ............................................................................................................ 45

8.3

Migrating from PROGRESS to ORACLE.................................................................................. 45

8.4

Customising QAD EA ................................................................................................................ 46

8.5

Substrings.................................................................................................................................... 46

9 .Net User Interface considerations .......................................................................................................... 47


10
QAD ICT Non intrusive customizations ............................................................................................ 48

Page |3

11
12

QAD Enterprise Financials customizations ....................................................................................... 50


Developers Self Service ........................................................................................................................ 51

Page |4

1 Introduction
The QAD GRC development endeavors, with regard to Progress/OE, to concentrate itself mainly
with QAD EA. Customization consists of new developments and adjustments of the existing
packages. All adaptations developed by QAD GRC will be based on the QAD GRC standard.
These programming standards don't always follow the programming standards of QAD inc. and
related products; If an existing standard program is customized, the existing code will not be
adapted. So more than one programming standard may occur in an adjusted program.
These programming standards are for various Progress/OpenEdge (and QAD EA ) releases. If a
certain standard is not valid for a certain release, its explicitly mentioned. Also in this manual
mandatory standards and recommendations are described; Mandatory standards must be used.
Recommendations should preferably be used.
The document itself explains the general programming standards. We are aware that the standard
will remain open to improvement. This document should reflect changes and developments. All
comments and ideas (in writing) are welcome.

Page |5

2 Database design
2.1 Table (database file)
Mandatory

Each table in a QAD EA database should have a unique prefix.


xxname_zzzz = unique identification where
xx
= The prefix is xx
name
= Free to use, should be the standard QAD EA table name for
shadow tables
zzzz = For new custom tables the following suffixes are suggested
mstr for master file
ctrl for control file
det for detail file
hist for history file
wkfl for work file
Recommendation

File names should be as close to 8 characters as possible.


Use include files for the dictionary deletion validation. This allows the deletion criteria
to be changed even if a database may be in use by other users. Simply edit the include
file and recompile the affected procedures.
Information

File names should be close to 8 characters for portability. Another reason to keep file names
short is that Progress/OE stores these names in the compiled R-code. Therefore, long names
have a direct impact on R-code size. This also applies to field, variable, temp & work table
names.
Example
pt_mstr
xxpt_mstr
xxerr_det

(QAD EA item table)


(Shadow Item table)
(New custom table)

2.2 Fields
Mandatory

Fields must have the same prefix as the corresponding file/table.


Domain field should be created, when applicable, for systems that are SE and above.
The domain field will have the same name as table name e.g. xxerr_det will have
xxerr_domain as the domain field.
For decimal fields, the number of decimals stored should be equal or greater than the
number of decimals displayed in the format.

Page |6

The format for logical data types should always have the positive format on the left and
the negative on the right. A format of "No/Yes" could cause severe logic problems.
Recommendation

Note that when you add a decimal field into database it has only 2 decimals by default.
Always consider to extend this number, e.g. to 10 decimals.
Use the format option with the data type char.
Be aware of the limitations of using the RECID (or ROWID ) data type. During a data
dump using EXPORT, the RECID is conveted to the unknown value (?). Using stored
RECIDS normally requires the developer to write custom load procedures.
Furthermore the bulkloader description file should be adjusted if fields with the RECID
datatype are used in the database. If the bulkloader file is created, the fields with RECID
datatype are not part of the file, this should be changed manually.
For character field formats, avoid using the "!" and "9" formatting characters unless a
character MUST be entered because Progress/OE does not allow a blank or nonalphabetic character when using this format.
COLUMN-LABELS should be the same width or less than the format of the field to act as
a "short label" for tight reports and screens. If screen space is limited do not stack
column labels more than 2 levels deep.
Information

Progress/OE does not check the syntax of a validation expression until a procedure is
compiled that utilises that expression. Whenever a VALEXP is entered or modified, the
expression can be checked by:
INSERT filename.
This will check the syntax of all the validation expressions in the file. Also remember
that the dictionary validation only applies to data entry statements (UPDATE, SET and
PROMPT-FOR, but not for event statements (ENABLE and DISABLE)).
Example

Date
:
Percentage :
Codes
:
Amount
Qty
:
Description

99/99/99
>>9.99%
"x(8)"
: ->>>,>>>,>>9.99
->>,>>>,>>9.9<<<<<<<<<
: "x(24)"

2.3 Indexes
Mandatory

The domain field (when it exists) should be the first field in all indexes.
The primary index should be the index that is used most often for traversing a file with a
FOR EACH, not the index mainly used for random access. This will cause the data to be

Page |7

dumped in that order. When the data is subsequently reloaded into a new database, the
RECID (ROWID) are assigned sequentially to the records during the load. When the
primary index is built, it will be build with references to these sequential RECIDs. All
other indexes will be built with the RECIDs in non-sequential order.
Do not create indexes whose components are exactly the same as the leading
components of another index.
Index A
Index B
Field A
Field A
Field B
Field B
Field C
Index B would usually be considered redundant in this example.
Information

Forgetting to define an important index to support a frequent access mode can cause poor
performance.

2.4 Database & Field triggers


Currently there are 5 database triggers; CREATE, DELETE, FIND & WRITE table
triggers and an ASSIGN field trigger. In std. QAD EA only DELETE & WRITE database
triggers are used. Replication triggers
should be created when needed . Triggers are not mandatory and should be created only
when a business reason exist for them.
Mandatory

Never use the over-rule option of a database trigger; If you define a database trigger with
the overrule option and a session (in a program) trigger, the database trigger will not fire
!! Make sure that always both triggers (if defined) are fired !! Currently the PROCON
triggers are the only exception on this.
Use the delete trigger for the deletion of related data, for example comments and detail
(line) information.
Don't give messages or allow user input in a trigger; Use return error instead and take
action in the calling procedure or event (use ERROR-STATUS:ERROR).
Don't use the CRC option with triggers because this requires that the source and the
object must be located in the same directory. Normally Progress/OE will search the
trigger program via the propath , but when using the startup -trig parameter, the relative
(trigger) location will be added to each propath entry to find the trigger program.
Information

Use of the WRITE or ASSIGN trigger is preferably because this trigger has access to the
old and new (changed) data (old + new buffer).

Page |8

Trigger references are dumped with the df file. The trigger code itself is a program and
can't be dumped or loaded.
All trigger definitions (object) can be up to 64K (not advisable).
More detailed information on triggers can be found in the Progress/OE Programming
Handbook (Chapter 10).

2.5 Sequences
Recommendation

Always set cycle on.


To create a sequence name, use the table prefix followed by an underscore, followed by
"sq" and a two digit sequential number that indicates the order the sequence was added
to the table. Start the sequence name with xx prefix to indicate that this is the custom
sequence.
For example: xxmrp_sq01
Sequence names can be up to 30 characters long (an Oracle limitation).
Information

A (cycle) sequence always gives a value; No checks are done if the current (in case of
the cycle) or previous value is used. Be aware that using sequences doesnt give a
correct number range because undo doesn't undo the sequence (don't use, for example,
sequences for invoice numbers).
Sequence (current) values are separately dumped using a QAD EA 36 menu option or
via the database administration functions (preferred).

2.6 Customizing databases


Standard QAD EA tables should never be altered. Here are only some general guidelines
given.
Recommendation

A custom database should be created to hold custom tables , indexes and sequences
If a new database table is created, also add some user & underscore fields for future use.
Also (re)create load and dump procedures when new tables are added (or changed) and
deliver them to the customer.
To create shadow tables use the template generated by ICT as starting point.

Information

In a standard QAD EA database two files (usrw_wkfl and mfc_ctrl) can be used for adding
new field and/or files.
All the fields except usrw_key3 can be used; usrw_key3 should contain the program name
(without .p) of the program where the records are created. QAD Inc uses the qad_wkfl,

Page |9

which has the same structure as usrw_wkfl, for temporary bug fixes. They use qad_wkfl to
store new field values or files, without changing the standard database structure. In the next
release the database structure will be changed and new files will be created.
If a new field or new parameter should be added to a control file, the file mfc_ctrl file can be
used. For example this file is used to store an additional printer name. The following code is
added in the sources:
create mfc_ctrl.
assign mfc_domain = global_domain
mfc_field
= "gl_stat_prt"
mfc_type = "C"
mfc_label = "Statem. of acct. printer"
mfc_module
= "FIN"
mfc_seq = 99.
Please note, the field is not added to the module control program; It must be added
manually!!

P a g e | 10

3 Naming conventions
3.1 General
All names should be in English language to serve the largest community of developers.
Mandatory

Use the "_" (underscore) character to connect words, prefixes and suffixes in the names
described below (except for internal procedures).
Use short but explicit names for identification.

3.2 External procedures (programs)


Mandatory
All custom codes should start with xx.
Recommendation

The following file name and extensions should be used for QAD EA procedures:
xxmmyyzz.x external procedure (program)
xx = fixed value
mm = module name
yy = program indication (free to choose)
zz = mt (maintenance), iq (inquiry), rp (report), up
(update) or
pm (control file maintenance.)
.x =

xxyz.t

xxyyyyyy.i

.p (developed via the Progress Editor) or .w


(developed via the User Interface Builder of
Progress)
database trigger program (See also STD-0032)
xxy
= unique identification, QAD EA table prefix
z
= Type of trigger, Delete, Write, Create, Find
and Assign.
include file, xx is a fixed string and yyyyyy is equivalent to
procedure name or self documented.

Clone of a standard program, for customization, should be named with xx prefix to the
standard program name.
Eg: xxsosomt.p

P a g e | 11

3.3 Internal procedures


Mandatory

Internal procedures should follow the verbNoun naming format


e.g. PROCEDURE getExchangeRate:
Recommendation

The name of the procedure is normally a short name of the procedure purpose.
Always use input & output parameters to call internal procedures and try to avoid the
use of local & shared variables.
Example

run checkItem (input pt_part, buffer xxpt_mstr, output lvl_ok, buffer tt_log).
PROCEDURE
define
define
define
define

checkItem:
input parameter
ipc_in_part
parameter buffer ipb_xpt_mstr
output parameter
ipl_out_ok
output parameter table

like pt_part
for xpt_mstr.
like mfc_log
for tt_log.

no-undo.
no-undo.

....
END PROCEDURE.

3.4 Functions
Mandatory

Functions should follow the verbNoun naming convention .


E.g . FUNCTION calculateAmount
Recommendation

The name of the function is normally a short name of the function performed.
Example

FUNCTION testWO return logical (input ipc_wo_nbr as


character).
....
RETURN true.
END FUNCTION.

if testWO(wo_nbr) = false
then do:
{pxmsg.i ....} /* .... */
next mainloop.
end.

3.5 Variables

P a g e | 12

Mandatory

Always use LIKE database field if the variable is related to a database field. Will raise
readability.
If logicals (Yes/No fields) are defined for UI, then use LIKE mfc_logical. This field has
the format of the database language. (STD-0044)
Give logicals a positive variable name; Use OK instead of NOTOK.
To distinguish local variables from database fields, a prefix should be used to set the
actual names off.
The prefix lv for local variable and sv for shared variable should be followed by
the data-type indicator character and an underscore.
c - Character
d - Decimal
t - Date
i - Integer
r - Recid
Parameters passed to internal or external procedure should have ip, op and iop prefix
Followed by the data-type character described above

Examples:

lvt_start_date
lvc_login_name
lvi_qty
svc_usr_name
ipc_curr_code
opd_exch_rate

Recommendation

Try to standardize the names of the variables. Use the following codes:
date
perc
qty
code
amt
desc
nbr
st

for
for
for
for
for
for
for
for

'date' fields
'percentage' fields
'quantity' fields
'code' fields
'amount' fields
'description' fields
'number' fields
'status' fields

3.6 Remaining Widgets (normally in character/GUI window programs)

P a g e | 13

Recommendation

The NetUI interface supports only the Fill-In data type OBCM widgets are not
supported.

3.7 Frames
Recommendation

As with variables, frame names should also have a prefix to set them off. In addition
the frame should be identified by type (local or shared). In multi-screen conversations,
the frame may also need to be numbered. Examples:
f_cust
(local) customer frame
fs_cust
shared customer frame
Selection frames of inquiry or reports should have a frame called "a" (see Chapter
concerning QAD EA includes).

3.8 Buffers
Recommendation

Buffers in external procedure should be used with prefix b_.


Internal procedures must define buffers for every table they reference, in this case, the
buffer name can be the same as the parent table name. A second buffer for the same
table may then use the b_ in its name.

3.9 Temporary Tables and Work Files


Mandatory

Always use temporary tables because you can define indexes on the temporary tables,
use like database table name option and temporary tables will put there data on disk if
memory is full. Workfiles dont have these features.
Always use the option NO-UNDO, in case UNDO processing is required use a
comment to identify the reason.
Recommendation

To distinguish temporary and work tables from database tables, prefix tt_ should be
used for temp-tables while workfiles can have wf_.
The fields of a temp-table should have a prefix of tt and work file fields should have
wf prefix.
Also if the temporary or work table represents a dictionary table, the temporary or work
table name should contain the dictionary table name. This will make it easier to locate
when doing text searches.
tt_so_mstr
ttso_nbr

temp table to store sales orders


field that belongs to a temp-table

P a g e | 14

3.10 Tables & Database


Mandatory

Because Progress/OE allows the construct db.table.field, it is mandatory that database


names and table/ buffer names be distinct to prevent confusion over database.table and
table.field.

Recommendation

Each table in the database shoud have a uique prefix.


xx<name_zzzz>
Where:
xx
name
zzzz

= The prefix is xx (see also the example)


= Free to use, should be the standard QAD EA table name for shadow
tables .
= For new custom tables the following suffixes are suggested
mstr for master file
ctrl for control file
det for detail file
hist for history file
wkfl for work file

3.11 Fields
Mandatory

Fields must have the same prefix as the corresponding table.


Recommendation

Fields should preferably adopt the name assigned to corresponding value in QAD
standard table.
Eg: Table Name: xxpt_mstr

Field Name: xxpt_um for the Unit of Measure.

3.12 Streams
Recommendation

Streams should also have a prefix lvs AND a suffix to identify input and output
streams:
lvs_rep_in
lvs_det_out

local input stream called report


shared output stream called detail

P a g e | 15

3.13 Block labels


Mandatory

Duplicate block labels are allowed in the same procedure, however, this practice is
discouraged because of the potential for confusion.
The first block label in a procedure should be called "mainloop" (the outside loop).
Recommendation

Block labels should have a prefix and should indicate the block contents:
trans_blk:
transaction block
level1_blk:
level1 block

3.14 Indexes
Mandatory

In domain(ed) systems an index must contain the domain field as the first field
When an index consists of only one field (apart from domain), the name of the index
should be the same as the field.
When an index has more than one component, the index should attempt to paraphrase
the fields used in the index
cp_part_cust

This describes the index that contains cp_part


(customer part) as the first component and cp_cust
(customer) as the second.

3.15 Prodataset
Mandatory

The name of the prodataset should be prefixed with ds


Special attention must be paid to ensure handles to prodatasets are deleted. This is to
prevent difficult to find memory leaks.
Always use the double colon notation to get field values. It is more legible.
Example : dsSales::tt_SalesOrder::ttSalesAmount

3.16 Labels and Messages


Recommendation

All custom messages should be created from the specified range of 21000 - 21999.
It is recommended that the messages be available in English.
Message Numbers in ranges 9000 to 9999 and 90000 to 99999 will be reserved
exclusively for our customers and distributors.
Labels should be preceded with the prefix QAD_CUST_.
Also, the label term and the text should be in English.

P a g e | 16

3.17 External References


Recommendation

When program output is directed to an ASCII file, the following naming conventions
should apply
 For portability, the file name should not exceed 8 characters. Only 3 character
suffix is allowed.
 To prevent collisions with other users who may also be writing ASCII files to
disk, one of the following conventions can be used:
- Write to the user's home directory, or
- Make the name of the file unique. Usually the TIME function with a
tiebreaker such as the QAD EA variable global_userid (or mfguser) is
sufficient to prevent naming conflicts.

3.18 Browses
Browses always have a name consisting of 2 letters and 3 numbers.
Custom browses should always start with xx (unless defined differently within the project) and
require a sequential number between 001 and 999.
When working in Browse maintenance, press the right mouse button on the Query or Header tab
and select: Show All tabs. The History tab now appears. In the history tab the following lines are
automatically created:
* $Revision: $ BY: Marcel Boertien DATE: 11/09/16 ECO: *XXXX*
In the XXXX area, enter the line next version of the browse. Use 1.0 for the first version and 1.1
for the next small change of a browse etc. Major changes will get a 2.0 number etc.

3.19 Reporting framework

All proxy programs are named CUST_XXX.p


The proxy programs read from two XML files fields definitions. The best practice is to
put only filter fields definitions in *. meta.xml and put all fields definitions in *. meta.all
file.
The naming convention is that the names of these XML files start with the same prefix.

Proxy
CUST_XXX.p

Filter Fields Definitions


CUST_XXX.meta.xml

All Fields Definitions


CUST_XXX.meta.all

P a g e | 17

4 Include files
4.1 General
Mandatory

Shared frames, buffers, variables etc. should be declared using an include file.
Include files should not terminate a block started outside of the include file. Conversely,
an include file should not start a block that ends outside of the include file.
Recommendation

Note that according to STD-0114 you should avoid using of shared variable. You
should not introduce a shared variable in a new program/procedure. If another
program or a procedure needs a variable, pass it as an input or input-output parameter.
Do not define variables within a procedure include file. The only exception is when the
include is especially developed for some purpose (i.e. Non-Intrusive development,
include: icdef.i).
Use standards include files whenever possible.
Named parameters rather than positional parameters should be used for new include
files, whenever parameters need to be passed to an include file.
It is recommended that include files not be nested more than 3 levels deep as debugging
can be difficult. Also the "explosion" of the include files seen when using the
COMPILE/LISTING option makes the code difficult to read
Example

/* Simple include */
{include.i}
/* Multiple named parameters */
{include.i &file-name
= pt_mstr
&frame-attr
= "no-box 2 columns"
&key
= pt_part }

4.2 QAD EA include files


Several standard QAD EA files can be used. Note that the Appendix (Non Intrusive)
contains example procedures where the different include files are used.
Type of include
General
"
Message
"
"

Include
mfdtitle.i
mfdeclre.i
pxmsg.i
mfphead2.i or
mfphead.i
mftrl080.i or

Needed for
main programs (variables definition)
sub-programs (variables definition)
standard messages (msg_mstr)
header for report with 80 or 132 columns
trailer for report with 80 or 132 columns (also contains

P a g e | 18

"
"
"
General
"
Call
"
General
inquiry/report
eB call
eB general
"

mfrtrail.i
mfreset.i
mfrpexit.i
mfquoter.i or
mfquoter.p
window1.i &
window2.i
mfnp*.i
gprun.i
gprunp.i
mfdel.i
gpselout.i
pxrun.i
gplabel.i
cxcustom.i

mfreset.i to
reset output
abort report
batch option

reset output to terminal)


to terminal
output
of report

scrolling window
browse through table with cursor keys
call external program
call internal procedure in persistent external program
deletion of (temp) table records
output selection for inquiry/report
call internal procedure
translation of frames
EPM code (contains pre-processors with code)

{mfdtitle.i "version number"} Normally only for main programs


Standardised titles should be displayed on the input frame by using {mfdtitle.i}. This
include file displays the procedure name, revision, menu title and date of execution. To
conform to other standard include files, all input fields used for selection criteria must be
displayed with frame a. The first parameter is the version number of this procedure. Note
that the include file {mfdeclre.i} is called in {mfdtitle.i}.
{mfdeclre.i} Only for non main programs
In this include several local and global variables are defined (setting is done in mf1a.p).
GLOBAL_PART and related global variables are used as the default value for part and
related fields, it is updated by maintenance programs and inquiries.
LOW_DATE, HI_DATE and HI_CHAR are variables used on many reports and
inquiries to evaluate selection criteria where a range of values are requested for input.
LOW_DATE is 01/01/1900, HI_DATE is 01/01/3999, HI_CHAR is set to a value
exceeding any character value which can be input on a keyboard. The variables may be
useful for setting or interpreting default values that are updated by the user.
STLINE, STSTATUS are variables to specify the text that appears on the status
(bottom) line of the screen. STLINE is an array with the following values, see STD0091:
 stline [1] = F1-Go F2-Help F3-Ins F4-End F7-Recall F8Clear F9_prev F10-Next
 stline [2] = F1-Go F2-Help F3-Ins F4-End F5-Delete F7Recall F8-Clear
 stline [3] = F1-Go F2-Help F3-Ins F4-End F7-Recall F8Clear

{mfphead.i or mfphead2.i} Report header


If the (default) output is sent to a printer, the report must contain a header (with program
name, version and QAD EA menu option). To print the header, use the {mfphead.i} for 132

P a g e | 19

columns reports or {mfphead2.i} for 80 columns reports. The header is repeated on each
page.
{mfphead.i}
or
{mfphead.i "stream str_log"}
{mfreset.i} - Close output
The first include will close the output and the message include will give a message that its
the end of the report. If an output is opened via a stream, the stream name is optional in the
"reset" include.
{mfreset.i}
{mftrl080.i or mfrtrail.i} - Report selection frame, close output
With use of these includes (for respectively 80 or 132 columns report), the selection values
of FRAME A will be printed and who requested the report. Than the output is closed. If the
output destination was scrolled output, the output is quotered into an ASCII file and this file
is viewed (character only). The same if the output is (hard coded) window for a GUI
environment. Note that when the output is opened via a stream, close it also with the same
stream name.
end. /* for each so_mstr */
/* REPORT TRAILER */
{mfrtrail.i "stream str_log"}
end. /* mainloop */
{mfrpexit.i} - Abort Report output
This includes checks whether the F4 or Esc key has been pressed during the printing of the
report. If so, a "Report aborted" message is printed and a LEAVE is performed. Note that is
mandatory that this include is only used within a FOR EACH block. The optional parameter
suppresses the "Report aborted" message;
{mfrpexit.i false}
end. /* each sod_det */
....
{mfrpexit.i}
end. /* end so_mstr */
/* REPORT TRAILER */
{mfrtrail.i}
end. /*mainloop */

P a g e | 20

{mfquoter.i or mfquoter.p} - Report output with a batch option, prepare for the batch
When a report must be executed in the QAD EA batch, the selection values must be saved
into the (global shared) variable BCDPARM. To save a selection value, use the
{mfquoter.i} includes. To save 20 selection values directly, use the mfquoter.p
program. Note that its mandatory that the sequence of saving the values must be identical
with the UPDATE or SET phrase.
bcdparm = "".
{gprun.i ""gpquote.p"" "(input-output bcdparm, 20,
nbr, nbr1, cust, cust1, string(ord),
string(ord1), spsn, spsn1,
po, po1, stat, stat1, quote, quote1, base_rpt,
string(mixed_rpt),
string(include_allocated),
string(include_picked),
string(include_shipped),
string(include_unprocessed))"}
{mfquoter.i print_options}
{mfquoter.i show_comments}
Note that the mfquoter.p program is used more often because each include takes a lot of
coding space (64K limit). Another option is an internal procedure with the mfquoter.i
includes.

{window1.i }
These include files can be used to create new scrolling window procedures. {window1.i}
is used to scroll through a single indexed field. {window2.i} permits the user to tab and
scroll through either of the two indexed fields.
{window1.i loc_mstr loc_loc loc_loc "use-index loc_loc"
yes
"Location Master"}
Note: The window1.i and windo2.i includes are applicable to ChUI only and do not work
with .NETUI .
The parameters for {window1.i} are:
1
File name
2
Field names surrounded by quotes to be displayed, including the indexed
field
3
Field name of indexed field (must be highest order field)
4
Index name displayed as "use-index pt_part"

P a g e | 21

5
Either "yes" or an expression surrounded by quotes to be used as selection
criteria
6
Frame title

Note that these window includes only work for 1 table. When using multiple tables, the
window includes cant be used. A workaround could be viewers & browsers.
Viewers & browsers Valid as of QAD EA
Browse Maintenance should be used to create browses and lookups. The NetUI version of
the program should be used to create the browses.
{mfnp.i ...}
The include file mfnp.i is one of several mfnp*.i include files which can be used to add the
capability to browse through a file using F9 (PREV) / cursor-up and F10 (NEXT) / cursordown. This include can only be used in an EDITING phrase. The editing phrase is added to
the end of the update statement. The FRAME-FIELD function is used to test an input field
to determine whether or not special action should take place. The include searches through
the table retrieves records using find next and/or find prev. At the beginning or end of the
table, (global shared) variable RECNO will be equal to ?.
update lvc_from_so
lvc_to_so
llv_detail
editing:
if frame-field = "lvc_from_so" then do:
{mfnp.i so_mstr lvc_from_so so_nbr lvc_from_so
so_nbr so_nbr}
if recno <> ? then
display so_nbr @ lvc_from_so.
end.
else if frame-field = "lvc_to_so" then do:
{mfnp.i so_mstr lvc_to_so so_nbr lvc_to_so
so_nbr so_nbr}
if recno <> ? then
display so_nbr @ lvc_to_so.
end.
else do:
readkey.
apply lastkey.
end.
end.
/* EDITING */

P a g e | 22

Note that here also the CASE statement could be used for checking the value of the FRAMEFIELD. The include file has six parameters:
1
File name
2
Input variable #1
3
Field corresponding to input variable #1
4
Input variable #2
5
Field corresponding to input variable #2
6
Index name
The values for the parameters 4 and 5 may be the same or different than those for parameter
2 and 3.
{gprun.i ....}
This include file can be used to call external procedure (or programs). Besides the program
itself, you give it input/output parameters and if the program must be called persistent (or
not).
{gprun.i 'sosomt.p'} or {gprun.i ""sosomt.p""'}
{gprun.i 'sosoa2.p' "(input so_nbr, output l_stat,
buffer tt_list"}}
{gprun.i "'nitrig' + string(l_i, '99') + '.p'"
" "
"persistent set
l_trig_handle[l_i]"}
{gprunp.i ....}
This routine is used to run an internal procedure contained in a persistent external procedure.
See an example below from sorp1001.p.
/*L024*
MASTER */
/*L024*/

GET ROUNDING METHOD FROM CURRENCY


{gprunp.i "mcpl" "p" "mc-get-rnd-mthd"
"(input so_curr,
output rndmthd,
output mc-error-number)"}

{mfdel.i ....}
With this include the deletion process of any (temp) table can be done faster because the
include makes a new transaction per 100 deleted records. Note that no transaction must
be started
{mfdel.i so_mstr "where so_due_date <= (today 100)"}
{mfdel.i tt_list}

P a g e | 23

{gpselout.i ....} -Inquiry/Report Output


This include replaces mfselprt.i and mfselbpr.i and contains named parameters.
Example from rcsorp10.p:
/*N03C*/
{gpselout.i
&printType = "printer"
&printWidth = prt_width
&pagedFlag = " "
&stream = " "
&appendToFile = " "
&streamedOutputToTerminal = " "
&withBatchOption = "no"
&displayStatementType = 1
&withCancelMessage = "no"
&pageBottomMargin = 6
&withEmail = "yes"
&withWinprint = "yes"
&defineVariables = "yes"}
{pxmsg.i ....} - Message
Include replaces most of the mfmsg*.i includes and contains named parameters
/* MESSAGE #8785 - ACTIVITY NOT ALLOWED FOR SUBPROJECT
*/
/* WITH STATUS # */
{pxmsg.i &MSGNUM=8785
&ERRORLEVEL={&APP-ERROR-RESULT}
&MSGARG1=projectLine.pjd_status
&FIELDNAME='projectLineId}
return error {&APP-ERROR-RESULT}.
/* Continue with procedure? */
confirm_yn = yes.
{pxmsg.i &MSGNUM
= 3140
&ERRORLEVEL = {&INFORMATION-RESULT}
&CONFIRM
= confirm_yn
{pxrun.i ....}
This include replaces gprunp.i.
Example from sosotrlf.p:
/* ROUND PER DOCUMENT CURRENCY ROUND METHOD */
{pxrun.i &PROC = 'mc-curr-rnd' &PROGRAM = 'mcpl.p'
&CATCHERROR = true
&PARAM = "(
input-output ext_actual,
input rndmthd,

P a g e | 24

output mc-error-number)"}

{gplabel.i} - External label include


This include contains functions which are needed for translation of labels in frames. The
include should be positioned after mfdeclre.i. Is already incorporated in mfdtitle.i.
{cxcustom.i ....}
This include contains all pre-processor definitions for all EPM code, Euro Accounting. If a
customisation on Euro Accounting is needed, it is possible you have to change this file. The
include has a parameter with the name of the program it is used in. For sorp1001.p :
/*N0WB*/ {cxcustom.i "SORP1001.P"}

P a g e | 25

5 Procedure structure
5.1 Header
Mandatory

The following item must be found in the header comments of any program
 Program name
 Author
 Purpose and general description of program
 Copyright
 Modification history:
- Date
- Who
- Change request number (i.e. SUI number, Requirement ID or Internal customer
reference)
Example New program

/*
/*
/*
/*

xxsampmt.p Procedure to extract customer data


Copyright 1986-2014 QAD Inc., Carpinteria, CA, USA.
All rights reserved worldwide. This is an unpublished work.
REVISION:1.1.18.1
LAST MODIFIED:08/26/13
BY:kmq
Q123456

*/
*/
*/
*/

Example Update an existing program (with customised software)


/* pxpgmmgr.p - Manages persistently run Progress programs
*/
/* Copyright 1986 QAD Inc. All rights reserved.
*/
/* $Id:: pxpgmmgr.p 15200 2012-02-23 20:06:30Z myb
$: */
/*
*/
/* Manages persistently run Progress programs
*/
/*
*/
/* Revision: 1.5
BY: Brian Wintz
DATE: 10/25/99
ECO: *N03S*
*/
/* Revision: 1.6
BY: Brian Wintz
DATE: 04/03/00
ECO: *N092*
*/
/* Revision: 1.7
BY: Brian Wintz
DATE: 04/18/00
ECO: *N03T*
*/
/* Revision: 1.8
BY: Murali Ayyagari
DATE: 05/25/00
ECO: *N0B9*
*/
/* Revision: 1.9
BY: Murali Ayyagari
DATE: 11/30/00
ECO: *N0V1*
*/
/* Revision: 1.10
BY: Murali Ayyagari
DATE: 01/04/01
ECO: *N0VM*
*/
/* Revision: 1.16
BY: Andrea Suchankova DATE: 03/05/02
ECO: *N13P*
*/
/* $Revision: 1.17 $ BY: Ashim Mishra
DATE: 03/3/10
ECO: *Q3W8*
*/
/* Revision: 1.0
BY: Joe D
DATE: 03/04/12 *CA990010*
*/
/*-Revision end---------------------------------------------------------------*/
/*
*/

5.2 Variables
Mandatory

Variables should not have the same name as a database field or a database for clarity.
All NEW SHARED/SHARED variables should be stored in include files passing NEW as
a parameter in the program where initially defined. This will make maintenance
easier and also prevent problems with conflicts in data type, NO-UNDO, EXTENT, etc.
{sosqvars.i new}

P a g e | 26

When defining variables, definition options should be aligned for readability. Example:

define variable lvc_name


as char format "x(10)"
label "Name"
no-undo.
define variable lvi_counter
as int format ">>>>9"
no-undo.
No variables should be defined in a statement other than a DEFINE statement.
Progress/OE allows variable definitions in DISPLAY, UPDATE, FORM and other data
handling statements, but they are difficult to locate and maintain when defined in this
way.
Recommendation

Note that according to STD-0114 you should avoid using of shared variable. You should not
introduce a shared variable in a new program/procedure. If another program or a procedure needs
a variable, pass it as an input or input-output parameter.

Variables should be described in the following order:


 System wide include file variables
 Application specific include file variables
 NEW GLOBAL SHARED
 NEW SHARED
 SHARED
 local
Variables should preferable be defined LIKE table.field-name whenever appropriate for
self-documentation and ease of maintenance. STD-0150
Try to list variables alphabetically to make locating them easier.
If possible all variables (and temp & work tables) should be defined as NO-UNDO. STD0103
Shared variable between programs should mostly be avoided. Parameters should be used
to pass values between programs.

5.3 Hard coded values / Pre-processors


Mandatory

Values used more than once in a procedure should be coded using a defined variable.
block_1:
for lvi_i = 1 to lvi_num:
.... transaction-1 .....
end. /* block_1 */
block_2:
for lvi_i = 1 to lvi_num:
.... transaction-2 .....
end. /* block_2 */

P a g e | 27

The same, but then with pre-processors (which at determined at compilation time and
NOT at executing time)
&SCOPED-DEFINE many_times 5
block_1:
for lvi_i = 1 to {&MANY_TIMES}:
.... transaction-1 .....
end. /* block_1 */
block_2:
for lvi_i = 1 to {&MANY_TIMES}:
.... transaction-2 .....
end. /* block_2 */

In newer versions of QAD EA the standard label


setFrameLabels functionality should be used and the use of pre processor is
deprecated.
form
code_fldname
colon 25
code_value
colon 25 format "x(30)" skip(1)
code_cmmt
colon 25
with frame a side-labels width 80 attr-space.
/* SET EXTERNAL LABELS */
setFrameLabels(frame a:handle).

Strings must not be hardcoded, messages come from msg_mstr, strings that require
mnemonics come from lngd_det, labels come from lbl_mstr.
Do not build sentences from separate text strings. Create new messages in msg_mstr for
displaying informational messages as well as errors and warning messages.

5.4 Other DEFINES


Recommendation

Other definitions should be described in the following order:


 new global shared stream
 new shared stream
 shared stream
 stream
 new shared buffer
 shared buffer
 buffer
 new (global) shared temp or work table
 shared temp or work table
 temp or work table

P a g e | 28








new shared frame


shared frame
frame
input parameter
output parameter
input-output parameter

5.5 Forms & Define Frame


Mandatory

NetUI interface uses standard ChUI code. GUI converted code is not to be used in
NetUI environments.
In GUI environments, never use the define frame statement because the GUI
converter doesnt convert the frame definition (it checks only the form
statements)
Always define a form for better performance and less coding.
All frame phrase options associated with a frame should be listed only on the form
statement for ease of maintenance.
All forms described in a program should be given explicit frame names. This is
particularly important because forms should be placed at the beginning of a program,
scooping them to the program block.

5.6 Change an existing program


Mandatory

All changes to a program should have a change request-number (i.e. SUI number,
Requirement ID or Internal customer reference). It is not allowed to delete the old
source code.

Recommended example Simple change of 1 or more lines


/*

lvi_a = 1.
lvi_a = lvi_b.

*MFG0409600*/
/*MFG0496000*/

Recommended example Block (many lines of coding) change


/*MFG0409600**START OF REPLACEMENT ********************************************
|
......
|
......
**MFG0409600**WITH*************************************************************/
......
......
/*MFG0409600**END OF REPLACEMENT***********************************************/

Recommended example Adding a few lines


/*MFG0409600*/ find xpt_mstr where xpt_part = pt_part
/*MFG0409600*/
exclusive-lock no-error.
/*MFG0409600*/ if available xpt_mstr then delete xpt_mstr.

P a g e | 29

Recommended example Adding a block (many lines of coding)


/*MFG0409600**START OF ADDITION************************************************/
......
......
/*MFG0409600**END OF ADDITION**************************************************/

Recommended example Deletion of a few lines


/*MFG0409600** find xpt_mstr where xpt_part = pt_part
/*MFG0409600**
exclusive-lock no-error.
/*MFG0409600** if available xpt_mstr then delete xpt_mstr.

**/
**/
**/

Recommended example Deletion of a block (many lines of code)


/*MFG0409600**START OF DELETION*************************************************
|
......
|
......
**MFG0409600**END OF DELETION**************************************************/

Note: If a lot of lines are put between comments (i.e. deleted), its recommended that each
deleted line should start with a | or *. This will give a better view of what has been commented
and what is real coding.

P a g e | 30

6 Procedure style
6.1 Indentation
Mandatory

Standard indentation is 3 spaces .


When the level of block nesting reaches to the point where lines are being "broken"
prematurely, 3 spaces indentation is allowed.
All statements contained within a block must be indented:
for each cm_mstr no-lock:
display cm_mstr.
for each so_mstr where so_domain = global_domain
and so_cust = cm_addr no-lock:
display so_mstr.
end. /* for each so_mstr */
end. /* FOR EACH CM_MSTR */

6.2 Statements per line


Mandatory

Only one statement per line is allowed for readability.


Recommendation

Try not to extend a statement by use of the tilde (~).

6.3 Capitalisation
Recommendation

All code will be in lower case with the exception of text inside a comment, preprocessor definitions and the CASE, FUNCTION and PROCEDURE statements.
See STD-0230.
Functions and Procedure names that use the verbNoun naming convention can use the
camel case e.g. getNextWorkOrder

6.4 Block Labels


Mandatory

All UNDO, RETRY, LEAVE & NEXT should explicitly indicate the target block.
If UNDO, RETRY, LEAVE, NEXT is used in the corresponding REPEAT, DO or FOR
EACH block, it should be preceded with a block label. The block label should describe
the function of the block.

P a g e | 31

Recommended

The label should be on a line by itself above the block header (see preceding example).

6.5 Punctuation
Mandatory

All statements should be terminated with periods except block labels and block headers
(FOR EACH/DO/REPEAT) which are terminated with a colon.

6.6 Comments
Recommendation

All block headers (FOR EACH/DO/REPEAT) should be preceded with a comment


describing the purpose of the block, especially if that block is a transaction block.
All end statements for blocks should be followed with a comment that "matches" the
end to the block header statement. The only exceptions would be blocks that contain
very few statements.
Example - Line comments should be of the form

/* THIS STYLE IS USED FOR LINE COMMENT


/* THIS ONE ALSO

*/
*/

6.7 Use of Dictionary Formats/Labels


Mandatory

For variables specify label and format in the define or FORM statement rather than on
data handling statements such as DISPLAY and UPDATE.
Recommendation

Use LABEL when defining side-labels and COLUMN-LABEL when defining column
labels.
If possible LABELS, FORMATS, VALIDATION and HELP from the data dictionary
should be used rather than overriding at the procedure level.

6.8 IF/THEN/ELSE & CASE


Mandatory

Only use not for testing positive named logical and standard functions like CANFIND, AVAILABLE, etc.
Always use DO and END directly around include files. Also with 1 line include files.
Else statements should appear on separate lines, aligned with the if statements to which
they apply.
For compound tests, align the ORs and ANDs.

P a g e | 32

If more that 2 nested IF/THEN/ELSES are used, the CASE statement is a good
alternative because the CASE statement doesnt has the limited of 15 nested
IF/THEN/ELSE
The use of "null" THENs and ELSEs is not allowed. The only exception for this is
when the program is running against an Oracle database.
IF RECID(MyRecord) <> ? then .

Recommendation

Mixed AND and OR conditions should be avoided, but if used the order of evaluation
should be explicitly noted through the use of parentheses.
Information

For a group of conditions connected by AND, the most unlikely condition(s) should be
tested first.
For a group of conditions connected by OR, the most likely condition(s) should be tested
first.
When testing logical fields or variables, explicitly test against TRUE, FALSE, YES and
NO rather than the implicit TRUE or FALSE value of the field.
NOT
BUT

if lvl_logical then
if lvl_logical = true then

NOT
BUT

if not lvl_logical then


if lvl_logical = false then

Example

if lvi_vara
lvi_varb
lvi_varc
do:
stmt1.
stmt2.
end. /* IF

= 1 and
> 2 and
< 30 then

lvi_vara*/

case lvd_a:
when 1 then do:
stmt1.
stmt2.
end. /* lvd_a = 1 */
when 2 then do:
stmt3.
stmt4.
end. /* lvd_a = 2 */
otherwise do:

P a g e | 33

stmt5.
stmt6.
end. /* REMAINING */
end case.

6.9 Listing Field Names


Mandatory

If common table names are going to be used between multiple databases, the convention
dbname.tablename.fieldname should be used. Avoid the use of the same table & field
names.
Lists of field names in a DISPLAY, UPDATE, FORM etc. should be shown as
follows.
 One field per line indented 3 spaces. Also if the frame phrase is used, it will be
aligned + 1 space with the starting statement.
update
so_nbr
so_cust
so_due_date
so_remarks
with frame ....

One field per line, but starting on the position of the first field.
update so_nbr
so_cust
so_due_date
so_remarks
with frame ....
Lists of field names and options in a form should be shown as follows; One field per line
and identical line options (types) starting at the same column.
form
so_nbr
at 1
label "SO Nbr"
so_cust
at 25
no-label
so_due_date to 60
no-label skip(1)
so_remarks colon 10
label "Rem"
with frame ....
Recommendation

When displaying a subset of an array, use the FOR option for arrays. This method is
easier to read and maintain than listing out each individual array element.
display array[1 for 5].

P a g e | 34

6.10 Keywords to be Aware of


Do not use

MESSAGE-LINES statement
Only returns the constant '2'.
VALIDATE statement, PAUSE statement and MESSAGE .....
VIEW-AS ALERT-BOX. statement in NetUI environments.
STOP statement
Useful for testing only.
ENTERED function
The entered flag is easily cleared by an UNDO, RETRY and could lead to incorrect
results.
USE-INDEX option
Essentially hard codes an index name into a procedure. Don't use unless knowledge of
data distribution shows that automatic index selection will be incorrect. Also because
multiple
indexes can be accessed by the database engine when use-index is not used.
Use

RELEASE statement
To be effective, release should be at the end of the transaction block (or the record
scope).
PAUSE 0 BEFORE-HIDE (be careful see STD-0039) and STATUS statements (see
STD-0091)
Realise that the changes these statements make to the default environment is inherited
by called procedures.

6.11 Abbreviations
Mandatory

Although abbreviations are supported, its recommended never to use abbreviations.

6.12 Frames
Mandatory

Frames should be standardized using the default box. Frames used for printed output
should use NO-BOX to recover the blank line that is allocated by default for the
"invisible" graphics box.
Frames should be 80 characters width.

P a g e | 35

6.13 Transaction
Mandatory

Block headers that define a transaction should explicitly use the transaction keyword for
self-documentation and to allow the compiler to catch possible transaction errors. When
there is no transaction, don't use the transaction keyword (because it always forces a
transaction to begin, although no database update will take place).

6.14 Error Handling


Mandatory

A hard error (e.g. entering a duplicate key into a unique index) should not send the user
back to the beginning of the block which is the default (UNDO BLOCK-LABEL, RETRY
BLOCK-LABEL). Instead more localised DO ON ERROR blocks along with NEXTPROMPT should be used to keep the cursor on the field where the error occurred.
The UNDO statement should never be used without a RETRY, NEXT, LEAVE OR
RETURN . Always follow the UNDO with the appropriate action (NEXT, LEAVE,
RETRY, RETURN). Always use a block-label.

6.15 Record Reading


Mandatory

For good style the left side of the comparison in a where clause will always be the field
used to retrieve the record.
NOT
BUT

find cm_mstr where "10" = cm_addr no-lock no-error.


find cm_mstr where cm_domain = global_domain and cm_addr = "10" no-lock no-

error.

When there are multiple conditions in the where clause, use the following forms:
for each cm_mstr where cm_domain = global_domain
and cm_addr >= "10"
and cm_addr <= "A" no-lock:

If FIND is used to retrieve the record, NO-ERROR and IF AVAILABLE should be


used.
The order of comparisons in a WHERE clause should follow this hierarchy.
1.
Fields of the index being used by the FIND/FOR EACH statement. The
comparisons should be in the same order as the fields occur in the index.
2.
Non-indexed fields.
3.
Variables.
4.
Expressions.
Do not use a FIND statement on a non-unique index or when all of the components of a
unique index are not supplied. Find is designed to retrieve a single record based upon

P a g e | 36

unique index information. Use FIND FIRST/NEXT/PREV/LAST for all other


situations.
Determine for each FIND/FOR EACH the expected average number of i/os for the
concerning index. The utility Promon can be used to count the number of read's. In
function 2 "Lock and Wait Statistics" under the label "Record" the number of reads is
shown.
If an index is not indicated by means of USE-INDEX, then first determine which index
would be used . If it is uncertain which index(es) will be used, a 'compile xref' file
should be created. In this file the chosen index(es) are displayed.
In domain(ed) environments for tables that have domain in them, the where clause
should match the field to global_domain. This prevents whole-index in the xref
output , thus care should be taken to confirm the correct index is used by the 4GL .
Recommendation

Do not use a FOR EACH block when retrieving a single record based upon a one-to-one
relationship. The use of FOR EACH when retrieving the item misleads one into thinking
that the sales order line <-> item relationship is one-to-many rather than one-to-one.
for each sod_det no-lock:
display sod_det.
for each pt_mstr where pt_domain = global_domain and
pt_part = sod_part no-lock:
display pt_mstr.
end.
end.

USING may be used instead of WHERE because USING specifies the key being used (in
combination with PROMPT-FOR).
If the transaction level and framing support it, all related records should be found in a
single for each statement.
for each cm_mstr no-lock,
each so_mstr where so_domain = global_domain and so_cust = cm_addr no-lock,
each sod_det where sod_domain = global_domain and sod_nbr = so_nbr no-lock:
display ....

Information

Be careful with the OR statement in selections with a FIND as well as FOR EACH loop.
Although Progress /OE has multiple indexing, an OR statement can causes a (partial)
sequential search. In the following example it won't lead to a sequential search through
the entire pt_mstr table.
for each pt_mstr where pt_domain = global_domain
and (pt_part = "12345"
<--- index search
or pt_part = "23456")
<--- index search
for each pt_mstr where pt_domain = global_domain
and pt_group = "AUTO" <--- index search
and (
pt_part = "12345" <--- index search

P a g e | 37

or pt_part

= "23456") <--- index search

Only use an OR statement:


 with non-key fields (is automatically sequential search)
 with key fields that are not passed through the index because the table is
approached through another table
 if the sequential search only consists of a few records
With from-up until selections make use of the default values in QAD EA. Use the
existing HI_CHAR, LOW_DATE and HI_DATE fields.
if lvc_part1 = hi_char then lvc_part1 = "".
if lvt_mdate = low_date then lvt_mdate = ?.
if lvt_mdate1 = hi_date then lvt_mdate1 = ?.
update lvc_group
lvc_group1
lvt_mdate
lvt_mdate1.
if lvc_part1 = "" then lvc_part1 = hi_char.
if lvt_mdate = ? then lvt_mdate = low_date.
if lvt_mdate1 = ? then lvt_mdate1 = hi_date.
for each pt_part where pt_domain =
and pt_part
and pt_part1
and pt_mod_date
and pt_mod_date
no-lock:

The assigning of the HI_CHAR, HI_DATE EN LOW_DATE fields can be done


efficiently in the following manner:
assign

global_domain
>= lvc_part
<= lvc_part
>= lvt_mdate
<= lvt_mdate1

lvc_part1 = if lvc_part1 = hi_char then "" else lvc_part1


lvt_mdate = if lvt_mdate = low_date then ? else lvt_mdate
lvt_mdate1 = if lvt_mdate1 = hi_date then ? else lvt_mdate1.

The MATCH statement always causes a (partial) sequential search. Only use matches:
 With non-key fields (is automatically sequential search)
 With key fields that are not passed through the index because the file is
approached through another file
 If the match search only consists of a few records
 Use, if possible, the begins instead of the matches statement
for each pt_mstr where
and
and
search
for each pt_mstr where
and
search
for each pt_mstr where
and

pt_domain = global_domain
pt_group =
"AUTO"
pt_part matches "123*"

<--- index search


<--- sequential

pt_domain = global_domain
pt_part matches "123*" ...

<--- sequential

pt_domain = global_domain
pt_part begins "123*" ...

<--- index search

P a g e | 38

Selecting the right index is not always easy. Progress/OE does have a so called "index
optimizer", but this uses the available "technical" search possibilities/index, but can not
functionally pass judgment.
Select an index from which as many fields as possible are used beginning with the first
field of the index. In the given example is a sequential search. Although 4 of the index
fields are used, LD_PART is the first field in the index and is not included in the
WHERE-clause! It is recommended to use LD_LOC_P_LOT in this case. Then (the first 2
fields) of the index will be used.
find first ld_det where ld_domain = global_domain
and ld_site
= "1000"
and ld_loc = "O/REP"
and ld_lot = "S12345"
and ld_ref = "0"
use-index ld_part_loc ...

Information

Using the FIELDS option can result in a better performance because when using this
option, only the related fields are sent to the (character/GUI) client and not all the fields
of that record. This can be especially handy for "big" records such as pt_mstr and
so_mstr.
for each pt_mstr fields (pt_part pt_desc1 pt_desc2) no-lock:
display pt_part pt_desc pt_desc2.
end.

If a field is missing in the fields declaration and it is used in the code a runtime error will occur.

6.16 Record Locking


Mandatory

Always use NO-LOCK if you do not want to update a record.


Always use EXCLUSIVE-LOCK if you do want to update a record.
SHARE-LOCK should preferable not be used. With SHARE-LOCK the possibility always
exists that deadly embrace (or deadlock) might occur. If SHARE-LOCK is used,
comment should explain why NO-LOCK or EXCLUSIVE-LOCK wasn't used.
To control the scope of the transaction the outer loop can
be run with no-lock and all the updates to the database
can be done in an internal procedure along with the
requisite release statement at the end of the procedure.

6.17 Use of Progress/OE functions


Mandatory

Always use standard functions whenever possible (i.e. CAN-DO, INDEX,


LOOKUP, DATE, TIME, ROUND).
Standard functions have been written in C and compiled to native mode. The interpreter
handles self-written functions.

P a g e | 39

6.18 Combine statements


Mandatory

Combine assignments as much as possible for better performance and saving R-code
space.

Example
NOT

lvd_a = lvd_b * lvd_x.


lvd_a = lvd_a + (lvd_c * lvd_y).
lvd_a = lvd_a / 3.

BUT
OR

lvd_a = ((lvd_b * lvd_x) + (lvd_c * lvd_y)) / 3.


assign lvd_a = lvd_b * lvd_x
lvd_a = lvd_a + (lvd_c * lvd_y)
lvd_a = lvd_a / 3.

6.19 Debugging
Recommendation

Use temporary debug statements to verify the flow of code and to locate the area where
a problem occurs, but dont forget to remove the debug message after testing !!
In versions of QAD EA where appservers are used the messages would be seen in the
appserver logs. The view-as alert-box clause is to be avoided as it would cause the
NetUI interface to block for input.
message "Im here".
Information

Progress/OE has a debug tool although it isnt commonly used.

6.20 Miscellaneous
Mandatory

Use algebraic style logical operators instead of mnemonics (Fortran style), see STD0214.
Always leave at least one space surrounding comparison and assignment operators.
STD-0234.
NOT
BUT

a NE b
a <> b

NOT
BUT

IF a>c THEN
IF a > c THEN

Recommendation

Hard coding of values into any program is discouraged with the following exceptions;
Parameters passed to an include file and unchanging constants (e.g. 12 months in a year)
.
When using DO WHILE/REPEAT WHILE loops, always test for a "less than" or "greater
than" condition rather than "equal to". This prevents infinite looping if the "equal to"
condition is never met.

P a g e | 40

Using REPEAT can result in creating an unnecessary and unwanted transaction. Use DO
instead of REPEAT in this case.
Use DEBLANK for data entry on any character field sensitive to leading blanks (i.e. sort
fields). TRIM function can be used too if available. Needed for Oracle db (STD-0012).
Information

Progress/OE cross-reference output is used to capture all run programs and uses of
"mfmsg...i" files so we can trace program and message usage. However Progress
cannot resolve what the value of variables may be during runtime so any gprun<>.i
or mfmsg<>.i that uses a variable for program or message cannot be resolved.
Please add extra comments (using if false then), with some examples of possible
variable values.
Example

if false then do:


{gprun0.i ""abc01.p""} /* added to meet the standard */
{gprun0.i ""abc02.p""} /* added to meet the standard */
{gprun0.i ""abc03.p""} /* added to meet the standard */
end.
{gprun.i "variable"} /* original code */

P a g e | 41

7 Portability
7.1 Terminals
Mandatory

Because the possibility exists that Programs may be run using terminals with a varying
number of available lines (25 for DOS, 24 for most ASCII terminals), use the following
functions to calculate the available lines and make maximum use of the available screen
space:
SCREEN-LINES
FRAME-DOWN
FRAME-ROW
FRAME-LINE
In the FRAME Phrase
expression DOWN
ROW expression
Do not use the COLOR statement.

WINDOW-HEIGHT
WINDOW-WIDTH
WINDOW-ROW
WINDOW-COLUMN

Recommendation

Use KEYFUNCTION instead of KEYLABEL for checking on certain function keys.


Use KEYLABEL instead of KEYFUNCTION for messages to the user.

7.2 Workfiles
Mandatory

The use of TEMP-TABLEs is preferred instead of WORKFILES. On 640K DOS


machines, there is very little memory available to allocate to local buffer space (the -l
parameter). The 64K barrier on local buffer size on DOS machines affects portability
when large numbers of WORKFILE records might be created. Because of this, the use of
WORKFILES is discouraged. If WORKFILES are needed the following conditions
should be met:
 The number of WORKFILE records created will remain static or not exceed a
predetermined "highwater mark".
 The WORKFILE records will not be increased in size during execution of the
procedure.

7.3 O.S. commands


Mandatory

The Progress OPSYS function must be used to enable programming to run under
different operating systems. Example:

P a g e | 42

CASE opsys:
when "UNIX" then do:
...
end.
when "WIN32" then do:
...
end.
END CASE.

Information

The following OS independent commands are available :


OS-COMMAND
OS-ERROR

OS-COPY
OS-RENAME

OS-DELETE

P a g e | 43

8 Oracle issues
8.1 Record creation and availability
Record creation behaviour and record availability can occur differently between a
PROGRESS database and an ORACLE database accessed through the data server.
Record creation behaviour and record availability can occur differently between a
PROGRESS database and an ORACLE database accessed through the
PROGRESS/ORACLE DataServer.
In native PROGRESS, the index blocks are populated as soon as the key information is
available. In ORACLE, a record is not available until it is "inserted" or "updated". The
PROGRESS/ORACLE DataServer does not insert records to the ORACLE database until
the end of the record scope, therefore making the record available at a later time than
native PROGRESS.
This difference causes a problem when coding with the PROGRESS/ORACLE
DataServer and assuming normal PROGRESS behaviour. A record created in a parent
procedure is not available to a called procedure, even if the primary key is used as the
search condition, because the PROGRESS/ORACLE DataServer has not written the
record to the database. A consequence is the called procedure tries to create the record the
parent had created. ORACLE will flag the duplicate record error once the two records are
actually being written to the database.
To solve this problem in the safest way, you can use the RECID-function. First usage of
the RECID function causes PROGRESS to create an index entry, thus assuring record
availability in sub-procedures. See also STD-0075.
We will show you two possible solutions to the problem, using the RECID function:
DEFINE VARIABLE MyVar AS RECID.
...
update-loop:
REPEAT WITH FRAME frmUpdate:
...
CREATE MyRecord.
ASSIGN MyRecord.KeyField1 = FirstValue
MyRecord.KeyField2 = SecondValue
MyVar = RECID(MyRecord).
/* This is the first method of forcing */
RUN NextProc(RECID(MyRecord)).
IF RECID(MyRecord) <> ? then .
END.

/* This is the second way of forcing

*/

/* This is the most used way of forcing */

In the above example, the solutions provided can be used together without causing any
problems.
Another way to solve the problem of record availability within an ORACLE environment
is to use one of the statements RELEASE or VALIDATE. A complication however is
that both statements do record validation and this might not be appropriate at that stage in
the program.

P a g e | 44

8.2 Length of database fields


All fields in an ORACLE database have a MAX-LENGTH size attribute. If you use
protoora to migrate a custom side database to ORACLE, you may need to correct the
MAX-LENGTH attribute before the data is loaded.
All fields in an ORACLE database have a MAX-LENGTH size attribute. In
PROGRESS, fields have a FORMAT size attribute, but the actual length stored in the
database can exceed the FORMAT length. In QAD EA, for example, several fields
exceed the FORMAT length because data is concatenated to the end of a field.
For the reason cited in above, the QAD EA on ORACLE database has the MAXLENGTH attributes sized to match the actual length of data and not the FORMAT
size. However, the protoora utility bases the MAX-LENGTH attribute on the
FORMAT attribute. If you use protoora to migrate a custom side database to
ORACLE, you may need to correct the MAX-LENGTH attribute before you load
data.

QAD EA on ORACLE includes a utility named utdbsize.p, which helps locate fields
that need the MAX-LENGTH setting increased.
Care should be taken with fields of data-type DECIMAL within an ORACE
environment. The protoora utility checks the format of a field to determine the scale
(= total length) and precision of its ORACLE counterpart NUMBER. The decimal
positions before the decimal point are regarded to be the scale and the decimal
positions after the decimal point are regarded to be the precission of the ORACLE
number field. The decimals-option for a PROGRESS decimal field is not taken in
consideration at all. Therefor a PROGRESS decimal field with a format of ">>>>,>>>,>>9.99" (16 pos.) and 3 decimals are converted by protoora to an
ORACLE number field with a scale of 14 and a precision of 2. There are 2 possible
solutions to this problem. Firstly: make sure the format reflects exactly what you want
the scale and precision to be in ORACLE and format the fields within your
application in the way you want them to see. Secondly: manually change the scale
and precision of the number fields in the ORACLE database to the desired scale and
precision.

Refer to the QAD EA on ORACLE Installation and Conversion Guide for more details.

8.3 Migrating from PROGRESS to ORACLE


When migrating a database from PROGRESS to ORACLE you need to use the
PROGRESS/ORACLE DataServer Utility prptppra.p; however, additional steps are
required to convert the database properly.
For additional information, see document 163 of the QAD Standards.

P a g e | 45

8.4 Customising QAD EA


When you are creating a new custom program, you may need to add tables or tablespaces to QAD EA on an ORACLE database. However, you should not modify the
standard QAD EA tables; only additions are recommended.
When you add ORACLE database objects, you must also add them to the PROGRESS
schema holder. To do this, use the PROGRESS/ORACLE DataServer utility,
Update/Add ORACLE Table Definitions. This utility uses the objects in the ORACLE
schema to create the PROGRESS schema holder. You can then compile your custom
code against the new schema holder.

8.5 Substrings
Substrings are the cause of many "record not found" errors. Using the TRIM function
can resolve this issue. Substrings are the cause of many "record not found" errors. If a
value does not meet the length passed to the SUBSTRING function, ORACLE fills it
with blanks. If this blank-padded value is compared to another value that is not blankpadded, the comparison fails.
To resolve this issue, you can use the TRIM function. See STD-0012.
find first pt_mstr where pt_domain = global_domain and
pt_prt = TRIM(SUBSTRING(part,10,8)) no-lock no-error.

P a g e | 46

9 .Net User Interface considerations


Mandatory

In QAD EA programs, avoid pause statement.


Use gpwait.i to simulate the effect of pause. For example, to explicitly pause the
display of frames that do only data display and no prompting. gpwait.i prevents the pause
statement from occurring by using a wait-for statement to simulate a pause.
Example:

for each cm_mstr no-lock:


display cm_addr with frame a down.
{gpwait.I &INSIDELOOP=YES &FRAMENAME=a}
end.
{gpwait.I &OUTSIDELOOP=YES}

Avoid making changes to the screen within an editing block.


Update fields in only one frame at a time.
All displayed frames should have setFrameLabels() function called after frame definition.
Do not separate labels from fields.
Use the appropriate status line values to get the required buttons.
Don't use VALIDATE in the data entry statements. Validations of input data should be
done in procedure code.
Use lookups created via Browse Maintenance for HELP lookups. Do not use scrolling
window lookups.
Do not use Progress browse widgets instead use scrolling window include files in
maintenance programs:
o swview.i
o swselect.i
Having multiple set/updates in frames can become cumbersome and cause long delays in
large programs.

Example:

SO Maintenance requires a user to hit F1 at least 30 times to complete a simple


2 line sales order. In .Net this can cause long delays. So when creating CHUI screen, keep in
mind that the same navigation will occur in .Net and that it is important to streamline it.

P a g e | 47

10 QAD ICT Non intrusive customizations


The QAD Integrated Customization Toolkit (QAD ICT) allows customizations to be
designed and developed in a non-intrusive way, eliminating or limiting required changes to the
original standard applications. As a result, custom development is faster to create and reduces
support costs, while retaining high quality standards. In addition, QAD ICT provides flexibility
to reuse customized functionality in other areas of your business and increases portability,
making it easier to migrate to new releases of QAD Enterprise Applications.
Typically, you encounter customization issues in the following areas:
System interface. Adding simple and complex validations, making whole frames or
selected values invisible for selected users, setting whole frames or selected fields as
read-only for selected users, defining initial/default values for selected fields, adding new
frames to the existing maintenance programs, adding new fields to already existing
frames.
Database schema. Adding shadow tables.
Processing. Adding new processing, changing how the system currently processes data.
New queries and reports.
Customizations are ordinarily connected with changes to source code. The obvious
disadvantages of that are:
Permanency. Changes are usually permanent; it is impossible to switch them on and off.
Access to source code. Necessity of having the full set of system source code. (The
standard QAD installation includes only source code for reports and inquiries.)
Difficulty with installing new patches. With intrusive customizations, the process of
installing new patches becomes difficult and time consuming.
Expensive upgrades. Extra work time is necessary to upgrade customizations to the
higher system version or service pack.
Many, many other disadvantages.
The QAD ICT solution helps you avoid such problems. Customizations:
Are much simpler
Avoid the need to have source codes necessity
Are significantly faster
Give you absolute control (ICT Debugger and Reports)
Are non-intrusive and system version/service pack independent
Repeatedly cost less
The QAD ICT solution is applicable to the operational modules only.
It is not applicable to Enterprise Financials.
The following factors should be considered before providing and ICT solution:
The customer may not want UI trigger based ICT to be used.

P a g e | 48

Customer may already have triggers and/or other functionality which could conflict with
ICT.

All the detail documentation to QAD ICT Toolkit is published on qad web pages
http://www.qad.com/documentlibrary/
QAD ICT training and certification is required.
Restrictions:

This section describes restrictionsactions that cannot be set up in QAD ICT. Please note that
these restrictions result from Progress and .NetUI limitationsnot QAD ICT itself.

Supported in
.NET UI

Supported in
CIM

On Entry on Field

No

No

On Leave on Field

No

No

On Go on Field

No

No

On Entry on Frame

Yes

No

On Go

Yes

No

GetFieldValue()

Yes

No

SetFieldValue()

Yes

No

GlobalValue()

Yes

No

Validation

Yes

No

Default Value

Yes

No

New fields on standard frame

Yes

No

Trigger

DMP files should be named <task_name>.dmp, where task_number is the change


request number (i.e. SUI number, Requirement ID or Internal customer reference)
Use 90.23.22 Domains by tasks and 90.23.23 Tasks by domains for ICT Tasks that
will be delivered to the customer carefully. These changes are dumped into .dmp file,
whilst domains on customer site have different names. As the result the customization
does not work on the customer environment and it is very hard to indicate the reason.
If changing anything in 90.24.24 ICT Control Table do it consciously. Once properly
defined the setting should not be changed.
Always use templates generated by ICT (for procedures and shadow tables
definitions).

P a g e | 49

11 QAD Enterprise Financials


customizations
Methods of customizations Enterprise Financials

User level customizations


Design mode (Enterprise Financials/Standard)
Changing of browses/report selections (Enterprise Financials)
Creation/modification of browses (Browse engine AppShell)
Creation/modification of process maps etc.
Modification of reports using QAD Report Framework
Non-intrusive customizations
Modification of reports:
Traditional Progress (traditional MFG/PRO)
QAD Report Framework
Crystal Reports
Customization layer (Business logic, new tables Enterprise Financials)
UI modifications/Custom components (new screens etc., Enterprise Financials)
ICT (business logic/screens traditional MFG/PRO)
API interfacing (QXtend, XML Daemon, Event Daemon, Enterprise Financials native
APIs)
Intrusive customizations
Traditional Progress (traditional MFG/PRO)
Additional APIs/hooks (Enterprise Financials, via R&D only)
BLF or changes to other core logic not available for customers (R&D only)

Methods to avoid in EF customizations

CIM loading
o black art, linked to old technology only, bug sensitive
Invasive code changes
o Break ability to implement support patches and lock customers into releases

QAD EE customizations training is required for QAD and Non-QAD developer as the first
step in EF customizations.

P a g e | 50

12 Developers Self Service


Recommendation

Performance tools are designed to identify common performance issues encountered by the
performance team on customer production systems and take less than one hour to run.
For more information access http://qdn.qad.com/display/RF/Performance+Developer+SelfService.

P a g e | 51

Вам также может понравиться