programming standards_march14.pdf

51
1 PROGRAMMING STANDARDS PROGRESS V7- OE10 QAD Enterprise Applications

Upload: babalawooggundaobara

Post on 19-Jul-2016

98 views

Category:

Documents


23 download

TRANSCRIPT

Page 1: Programming Standards_March14.pdf

1

PROGRAMMING STANDARDS

PROGRESS V7- OE10

QAD Enterprise Applications

Page 2: Programming Standards_March14.pdf

P a g e | 2

Contents

1 Introduction ................................................................................................................................................ 5

2 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

3 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

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

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

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

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

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

5.2 Variables ..................................................................................................................................... 26

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

Page 3: Programming Standards_March14.pdf

P a g e | 3

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

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

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

6 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

7 Portability .................................................................................................................................................. 42

7.1 Terminals .................................................................................................................................... 42

7.2 Workfiles..................................................................................................................................... 42

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

8 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 4: Programming Standards_March14.pdf

P a g e | 4

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

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

Page 5: Programming Standards_March14.pdf

P a g e | 5

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, it’s 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 6: Programming Standards_March14.pdf

P a g e | 6

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 (QAD EA item table)

xxpt_mstr (Shadow Item table)

xxerr_det (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 7: Programming Standards_March14.pdf

P a g e | 7

• 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

RECID’S 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 non-alphabetic 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 : 99/99/99

Percentage : >>9.99%

Codes : "x(8)"

Amount : ->>>,>>>,>>9.99

Qty : ->>,>>>,>>9.9<<<<<<<<<

Description : "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 8: Programming Standards_March14.pdf

P a g e | 8

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 RECID’s. All

other indexes will be built with the RECID’s 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 9: Programming Standards_March14.pdf

P a g e | 9

• 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 doesn’t 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 10: Programming Standards_March14.pdf

P a g e | 10

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!!

Page 11: Programming Standards_March14.pdf

P a g e | 11

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 = .p (developed via the Progress Editor) or .w

(developed via the User Interface Builder of Progress)

xxyz.t database trigger program (See also STD-0032) xxy = unique identification, QAD EA table prefix z = Type of trigger, Delete, Write, Create, Find

and Assign. xxyyyyyy.i 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

Page 12: Programming Standards_March14.pdf

P a g e | 12

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 checkItem:

define input parameter ipc_in_part like pt_part no-undo.

define parameter buffer ipb_xpt_mstr for xpt_mstr.

define output parameter ipl_out_ok like mfc_log no-undo.

define output parameter table for tt_log.

....

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

Page 13: Programming Standards_March14.pdf

P a g e | 13

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 for 'date' fields

perc for 'percentage' fields

qty for 'quantity' fields

code for 'code' fields

amt for 'amount' fields

desc for 'description' fields

nbr for 'number' fields

st for 'status' fields

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

Page 14: Programming Standards_March14.pdf

P a g e | 14

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 it’s 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 don’t 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 temp table to store sales orders

ttso_nbr field that belongs to a temp-table

Page 15: Programming Standards_March14.pdf

P a g e | 15

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 = The prefix is xx (see also the example)

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

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 local input stream called report

lvs_det_out shared output stream called detail

Page 16: Programming Standards_March14.pdf

P a g e | 16

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.

Page 17: Programming Standards_March14.pdf

P a g e | 17

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 Filter Fields Definitions All Fields Definitions

CUST_XXX.p CUST_XXX.meta.xml CUST_XXX.meta.all

Page 18: Programming Standards_March14.pdf

P a g e | 18

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 Include Needed for

General mfdtitle.i main programs (variables definition)

" mfdeclre.i sub-programs (variables definition)

Message pxmsg.i standard messages (msg_mstr)

" mfphead2.i or

mfphead.i

header for report with 80 or 132 columns

" mftrl080.i or trailer for report with 80 or 132 columns (also contains

Page 19: Programming Standards_March14.pdf

P a g e | 19

mfrtrail.i mfreset.i to reset output to terminal)

" mfreset.i reset output to terminal

" mfrpexit.i abort report output

" mfquoter.i or

mfquoter.p

batch option of report

General window1.i &

window2.i

scrolling window

" mfnp*.i browse through table with cursor keys

Call gprun.i call external program

" gprunp.i call internal procedure in persistent external program

General mfdel.i deletion of (temp) table records

inquiry/report gpselout.i output selection for inquiry/report

eB call pxrun.i call internal procedure

eB general gplabel.i translation of frames

" cxcustom.i 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 STD-0091:

� stline [1] = F1-Go F2-Help F3-Ins F4-End F7-Recall F8-

Clear F9_prev F10-Next

� stline [2] = F1-Go F2-Help F3-Ins F4-End F5-Delete F7-

Recall F8-Clear

� stline [3] = F1-Go F2-Help F3-Ins F4-End F7-Recall F8-

Clear

{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

Page 20: Programming Standards_March14.pdf

P a g e | 20

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 it’s 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 */

Page 21: Programming Standards_March14.pdf

P a g e | 21

{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 it’s 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"

Page 22: Programming Standards_March14.pdf

P a g e | 22

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 can’t 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) / cursor-

down. 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 */

Page 23: Programming Standards_March14.pdf

P a g e | 23

Note that here also the CASE statement could be used for checking the value of the FRAME-

FIELD. 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* GET ROUNDING METHOD FROM CURRENCY

MASTER */

/*L024*/ {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}

Page 24: Programming Standards_March14.pdf

P a g e | 24

{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,

Page 25: Programming Standards_March14.pdf

P a g e | 25

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"}

Page 26: Programming Standards_March14.pdf

P a g e | 26

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}

Page 27: Programming Standards_March14.pdf

P a g e | 27

• 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. STD-0103

• 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 */

Page 28: Programming Standards_March14.pdf

P a g e | 28

• 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

Page 29: Programming Standards_March14.pdf

P a g e | 29

� 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 doesn’t 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. *MFG0409600*/

lvi_a = lvi_b. /*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.

Page 30: Programming Standards_March14.pdf

P a g e | 30

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), it’s 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.

Page 31: Programming Standards_March14.pdf

P a g e | 31

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, pre-

processor 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.

Page 32: Programming Standards_March14.pdf

P a g e | 32

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 CAN-

FIND, 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 OR’s and AND’s.

Page 33: Programming Standards_March14.pdf

P a g e | 33

• If more that 2 nested IF/THEN/ELSE’S are used, the CASE statement is a good

alternative because the CASE statement doesn’t has the limited of 15 nested IF/THEN/ELSE

• The use of "null" THEN’s and ELSE’s 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 if lvl_logical then

BUT if lvl_logical = true then

NOT if not lvl_logical then

BUT if lvl_logical = false then

Example

if lvi_vara = 1 and

lvi_varb > 2 and

lvi_varc < 30 then

do:

stmt1.

stmt2.

end. /* IF 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:

Page 34: Programming Standards_March14.pdf

P a g e | 34

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].

Page 35: Programming Standards_March14.pdf

P a g e | 35

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, it’s 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.

Page 36: Programming Standards_March14.pdf

P a g e | 36

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 NEXT-

PROMPT 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 find cm_mstr where "10" = cm_addr no-lock no-error.

BUT 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

Page 37: Programming Standards_March14.pdf

P a g e | 37

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/o’s 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 read’s 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

Page 38: Programming Standards_March14.pdf

P a g e | 38

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 = global_domain

and pt_part >= lvc_part

and pt_part1 <= lvc_part

and pt_mod_date >= lvt_mdate

and pt_mod_date <= lvt_mdate1

no-lock:

• The assigning of the HI_CHAR, HI_DATE EN LOW_DATE fields can be done efficiently in the following manner:

assign 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 pt_domain = global_domain

and pt_group = "AUTO" <--- index search

and pt_part matches "123*" <--- sequential

search

for each pt_mstr where pt_domain = global_domain

and pt_part matches "123*" ... <--- sequential

search

for each pt_mstr where pt_domain = global_domain

and pt_part begins "123*" ... <--- index search

Page 39: Programming Standards_March14.pdf

P a g e | 39

• 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.

Page 40: Programming Standards_March14.pdf

P a g e | 40

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 lvd_a = ((lvd_b * lvd_x) + (lvd_c * lvd_y)) / 3.

OR 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 don’t 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 "I’m here". Information

• Progress/OE has a debug tool although it isn’t commonly used.

6.20 Miscellaneous

Mandatory

• Use algebraic style logical operators instead of mnemonics (Fortran style), see STD-0214.

• Always leave at least one space surrounding comparison and assignment operators. STD-0234.

NOT a NE b NOT IF a>c THEN

BUT a <> b BUT 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.

Page 41: Programming Standards_March14.pdf

P a g e | 41

• 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 */

Page 42: Programming Standards_March14.pdf

P a g e | 42

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 WINDOW-HEIGHT

FRAME-DOWN WINDOW-WIDTH

FRAME-ROW WINDOW-ROW

FRAME-LINE WINDOW-COLUMN

• In the FRAME Phrase expression DOWN

ROW expression

• Do not use the COLOR statement. 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:

Page 43: Programming Standards_March14.pdf

P a g e | 43

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-COPY OS-DELETE

OS-ERROR OS-RENAME

Page 44: Programming Standards_March14.pdf

P a g e | 44

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)). /* This is the second way of forcing */

IF RECID(MyRecord) <> ? then . /* This is the most used way of forcing */

END.

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.

Page 45: Programming Standards_March14.pdf

P a g e | 45

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 MAX-LENGTH 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.

Page 46: Programming Standards_March14.pdf

P a g e | 46

8.4 Customising QAD EA

When you are creating a new custom program, you may need to add tables or table-spaces 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 blank-padded, 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.

Page 47: Programming Standards_March14.pdf

P a g e | 47

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.

Page 48: Programming Standards_March14.pdf

P a g e | 48

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.

Page 49: Programming Standards_March14.pdf

P a g e | 49

• 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 restrictions—actions that cannot be set up in QAD ICT. Please note that these restrictions result from Progress and .NetUI limitations—not QAD ICT itself.

Trigger

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

• 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).

Page 50: Programming Standards_March14.pdf

P a g e | 50

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 API’s)

• Intrusive customizations

• Traditional Progress (traditional MFG/PRO)

• Additional API’s/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.

Page 51: Programming Standards_March14.pdf

P a g e | 51

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+Self-Service.