BaanERP Tools - Programming Features PDF
BaanERP Tools - Programming Features PDF
BaanERP Tools - Programming Features PDF
Programming features
A publication of:
Baan Development B.V.
P.O.Box 143
3770 AC Barneveld
The Netherlands
1 Introduction 1-1
3GL scripts 1-1
4GL UI and DAL scripts 1-1
Report scripts 1-2
Baan SQL 1-2
Dynamic-link libraries 1-2
BaanERP debugger 1-2
Multitasking 1-3
3GL/4GL functions 1-3
2 3GL programming language features 2-1
Overview 2-1
Vocabulary 2-1
Character set 2-1
Continuation symbol 2-1
Comment 2-1
Separators 2-2
Reserved words 2-2
Constants 2-3
Numeric constants 2-3
String constants 2-4
Symbolic constants 2-4
Enumerate and set constants 2-4
Variables 2-5
Data types 2-6
Declarations 2-6
Tables 2-7
Domains 2-8
Arrays 2-9
Fixed and based variables 2-12
Multibyte strings 2-13
Bidirectional strings 2-14
Common variables 2-14
NULL characters in strings 2-15
Expressions and operators 2-16
Arithmetic operators 2-17
Relational operators 2-18
Programming features
i
Table of contents
Programming features
ii
Table of contents
Programming features
iii
Table of contents
Programming features
iv
Table of contents
Programming features
v
Table of contents
Programming features
vi
Table of contents
Programming features
vii
Table of contents
10 Errors 10-1
UNIX errors 10-1
Database errors 10-6
11 Known limits 11-1
Reports 11-1
Bshell 11-1
Bic 11-1
SQL 11-1
Tables 11-1
Indexes 11-2
12 ASCII table (ISO 8859-1) 12-1
13 Index 13-1
Programming features
viii
About this document
This document describes the main features of the Baan 3GL/4GL programming
language. Programming functions are described in a separate document:
BaanERP Tools: Functions Reference (document number: U7167A US).
Summary
Chapter 1 provides a brief introduction to Baan 3GL/4GL programming features.
Chapter 2 describes in detail the features of the Baan 3GL programming
language.
Chapter 3 describes the 4GL language features for BaanERP Tools. In particular
it describes the 4GL event sections used in Baan 4GL program scripts. It also
describes the flow of the standard program, and it discusses the automatic import
of variables
Chapter 4 describes the functionality available for creating report scripts.
Chapter 5 provides information about database handling and describes Baan SQL
in detail.
Chapter 6 describes in detail the Data Access Layer (DAL) and the functionality
available for creating DAL scripts.
Chapter 7 describes how the bshell provides a multitasking execution
environment for BAAN applications. It provides information about the Bshell
scheduler, context switches, events, requests, inquiries and replies, process and
process groups, and process synchronization.
Chapter 8 discussion the use of Dynamic Link Libraries (DLLs) in Baan
applications.
Chapter 9 provides information on the Baan Debugger.
Chapter 10 lists and describes operating system and database errors.
Chapter 11 lists the known limits that apply to Baan applications.
Chapter 12 presents an ASCII table (ISO 8859-1).
Programming features
ix
Table of contents
Typographical conventions
The following conventions are used in this manual:
bold Bold type is used for the names of functions, 4GL event
sections, and predefined variables, when these are included in
descriptive text.
italics Italics are used for the names of function arguments, when
these are included in descriptive text. Italics are also used for
other non-literals, for emphasis in the text, and for the titles of
publications.
monospace Monospace type is used for the syntax of functions,
declarations, expressions, SQL statements, and so on, for
program startup commands, and for code examples.
Acronyms
CDAS Common Data Access Server
DAL Data Access Layer
DAM Data Access Methods
DLL Dynamic-link library
RDBMS Relational Database Management System
SQL Structured Query Language
STP Standard Program
UI User Interface
Related documents
BaanERP Tools: Functions Reference (document number: U7167A US)
This document describes in detail the functions available for developing
BaanERP applications with the Baan 3GL/4GL programming language.
BaanERP Tools: Programming Features online
This document is available online as a Microsoft Windows help file. The help
file includes the document BaanERP Tools: Functions Reference. Both the help
file and the printed manuals are similarly organized. However, the help file
includes numerous hypertext links to facilitate navigation, and a comprehensive
index and full text search facility.
You can access the help file by choosing the Manual Pages option on the
Specific menu of the session Program Scripts (ttadv2530m000). The name of the
help file is tt_mp2.hlp.
Programming features
x
1 Introduction
3GL scripts
3GL scripts are program scripts that are either linked to sessions without forms
or not linked to sessions at all. They do not have any relationship with the 4GL
Engine (previously known as the Standard Program or STP). When creating such
scripts, you must specify the entire program flow, including the main function.
You cannot use 4GL event sections or functions. Chapter 2, 3GL programming
language features, describes the 3GL programming language in detail.
Programming features
1-1
Introduction
The Data Access Layer (DAL) now handles database interaction. Programmers
create a user interface (UI) script to change the default behavior of a session.
They create a DAL script to program all the logical integrity rules for a particular
table.
Chapter 3, 4GL programming features, describes the 4GL event sections that you
can use in UI scripts. Chapter 6, Data Access Layer, describes the event sections
and DAL functions that you can use in DAL scripts.
The statements programmed in event sections can be a combination of 3GL/4GL
functions and 3GL language statements.
Report scripts
Report scripts are 4GL scripts that are linked to a report in order to add to or
modify its output. In a report script, you can program actions that you want to be
performed at particular stages of the report execution. Chapter 4, Report scripts,
describes the event sections and report functions that you can use in report
scripts.
Baan SQL
You can use Baan SQL (Structured Query Language) in 4GL scripts to retrieve
data from database tables. There are two ways to use Baan SQL in a 4GL
program. You can embed it in the language (embedded SQL), or you can use
BaanERP 4GL functions (dynamic SQL). Chapter 5, Database handling,
describes both options in detail.
Dynamic-link libraries
BaanERP Tools supports the use of dynamic-link libraries (DLLs). A DLL
consists of a library of functions that is compiled and stored separately from the
processes that use the library. Each program that uses a DLL links to it at
runtime. Chapter 8, Dynamic-link libraries, describes the use of DLLs in
BaanERP applications.
BaanERP debugger
When you compile your programs, you can use the BaanERP debugger to control
and test their execution. Chapter 9 provides an overview of the debugger and
describes the numerous options it supports.
Programming features
1-2
Introduction
Multitasking
The bshell (also referred to as the Baan Virtual Machine) provides a multitasking
execution environment for BaanERP applications. Each bshell can execute and
schedule multiple parallel processes. Chapter 7, Multitasking and the GUI,
provides an overview of how processes and user interface interaction are
managed by the bshell.
3GL/4GL functions
BaanERP 3GL and 4GL functions are described in a separate document:
BaanERP Tools: Functions Reference (document number U7167A US).
Programming features
1-3
Introduction
Programming features
1-4
2 3GL programming language features
Overview
This section describes the features of the Baan 3GL programming language. You
can use the 3GL language in both 3GL scripts and 4GL scripts.
Vocabulary
Character set
You can include the following characters in a 3GL language statement:
n The full alphabet – a-z and A-Z
n The digits 0-9
n The characters # $ ^ & * ( ) - _ + = { } [ ] | \ ; : " , . / < >
This document uses uppercase characters to indicate keywords. However, this is
not necessary in your programs.
Continuation symbol
If a statement does not fit on one line, you can split it across two or more lines.
There is no limit to the number of lines that you can use for one statement.
Wherever you can include a space, you can also make a new line.
There are two exceptions: a string constant and a macro definition. If these do
not fit on one line, you must place a caret symbol [^] at the beginning of the
second and subsequent lines. You can use the caret symbol in other statements
also, but this is not necessary.
Comment
The pipe symbol [|] indicates that the text from the symbol to the end of the line
must be handled as a comment. The compiler ignores this text. Good comments
help the reader of a program source to understand the program better.
Programming features
2-1
3GL programming language features
Separators
You can use tabs, newlines, and spaces as separators in your program.
Reserved words
The Baan 3GL programming language includes a number of words with defined
meanings. These are reserved words that you cannot use other than in the context
for which they were designed. Not all these words are described in this
document; some are for internal use or for compatibility with older releases.
The following is a list of these reserved words:
AND END IN SELECTBIND
AT ENDCASE INPUT SELECTDO
BASE ENDFOR LE SELECTEMPTY
BASED ENDIF LONG SELECTEOS
BREAK ENDWHILE LT SELECTERROR
BSET ENDSELECT MB STATIC
CALL ENDDLLUSAGE MULTIBYTE STEP
CASE EQ NE STOP
COMMON EXTERN NOT STRING
CONST FALSE ON TABLE
CONTINUE FIXED OR THEN
DEFAULT FOR PRINT TO
DIM FUNCTION PROMPT TRUE
DLLUSAGE GE REF UNTIL
DOMAIN GLOBAL REFERENCE VOID
DOUBLE GOTO REPEAT WHEREBIND
ELSE GT RETURN WHEREUSED
EMPTY IF SELECT WHILE
Programming features
2-2
3GL programming language features
Constants
A constant is a value of a special type that you can assign to a variable. The Baan
3GL programming language supports the following types of constants:
n Numeric constants
n String constants
n Symbolic constants
n Enumerate / set constants
Numeric constants
The Baan 3GL programming language supports long and floating point
constants. Both types can be preceded by a ’+’ or a ’-’ sign.
Long constants
A long constant consists of the digits 0-9 only. For example:
12345
-530
0xFFF (hexadecimal)
Programming features
2-3
3GL programming language features
String constants
A string constant is a number of displayable single-byte or multibyte characters
enclosed by double quotation marks. A string constant with length zero (that is,
an empty string) is indicated by two adjacent quotation marks. To include a
double quotation mark within a string constant, you must include two adjacent
double quotes.
For example:
"This is a string constant"
""
"A quote "" within a string constant"
"This is a very long string constant whic
^h does not fit on one line"
Symbolic constants
A symbolic constant is used in your program as a symbolic name, but at runtime
it has a fixed value. The defined constants are:
FALSE | The actual value is 0
TRUE | The actual value is 1
PI | The actual value is 3.141592653589793
Note that if FALSE and TRUE are used as boolean values (for example, as a
result of expressions), they mean zero and not zero respectively.
box_color = color.green
box_color = color.red
Programming features
2-4
3GL programming language features
For working with sets, see also the bit functions in U7167A US BaanERP Tools:
Functions reference.
A special constant of type enumerate or set is EMPTY. This indicates an empty
set or an enumerate which is not defined. Internally, it has the value 0.
Variables
The name of a variable is used to indicate the memory location where data
(characters, numbers, and so on) is stored. The name of the variable refers to the
associated data.
The value of a variable can change during execution of the program. A variable
belongs to a data type and must be declared before its use. This is usually done at
the start of the program. In some cases initialization of the declared variables is
necessary. The default initial value is always zero for longs and doubles, and an
empty string for strings.
The name of a variable can consist of any number of letters, digits, underscores
[_], and periods [.]. It must begin with an alphabetic character.
You should keep the following in mind when naming a variable:
n The name of a variable must not be the same as a reserved word or a
previously declared variable.
n The name of the variable must give an indication of its contents. It is good
practice to indicate the purpose of a variable beside its declaration, in the
form of comments.
n A variable must not be used for a purpose other than the one for which it was
originally intended.
Programming features
2-5
3GL programming language features
Data types
There are five types of variables: long, double, string, table, and domain
variables.
n Long variables can contain any whole number from -2147483648 to
2147483647. For numbers beyond this range, use double variables instead.
Physically, four bytes are reserved for each long variable.
n Double variables are used for any number containing a decimal point, with a
maximum of 15 significant digits (8 bytes).
n A string variable contains a string constant. The maximum length of a string
is 1024 characters.
n A table variable is used for database tables in your program. The table must
be defined in the data dictionary.
n A domain variable is a variable of a certain type that is defined in the data
dictionary. Each of the following types are possible: long, byte, integer, date,
enumerate, set, float, double, string, text. Each domain defined in the data
dictionary can be used in a declaration of your program. See also “Domains”
later in this chapter.
Declarations
You can declare variables either within a function block or at the start of the
program. Variables declared in a function block can be used within that function
block only. Variables declared at the start of the program can be used in each
function described below the declaration.
General syntax
You declare variables with the following syntax (parts between [ ] are optional):
[ special ] <type> <variable> [ option ] [, <variable>
[ option ], ...]
Programming features
2-6
3GL programming language features
The following are the possible values for the various parts of a variable
declaration:
special EXTERN | Not in function blocks
STATIC | Only in function block; see
| "Functions" later in this chapter.
type LONG
DOUBLE
STRING
TABLE
DOMAIN <domain name> | domain name is a domain
| defined in the data
| dictionary
variable The syntax for <variable> is:
<name>[(<expression>,...)]
option BASED | (only for arrays)
FIXED
MB | (multibyte)
You can declare several variables of the same type in the same statement. To do
so, simply include commas between the variable names.
If a variable is to be accessed by its symbolic name from outside the program, it
must be declared with the keyword EXTERN, so that the variable name is stored
in the symbol table of the object.
You must declare a variable with the keyword EXTERN if that variable is used
within other programs, within forms (field names and variables within
expressions), or within the function expr.compile(). If the functions get.var()
and put.var() are used within the program, the variables in the other program
must be declared as EXTERN.
Tables
If you use database tables and records in your program, you must declare the
tables as follows:
TABLE <table name> | table name must start with a ’t’.
Programming features
2-7
3GL programming language features
Domains
When declaring temporary variables for storing values of database fields, you
can use normal variables of type long, double, or string. But this can cause
problems if the length or type of the table field has been changed in the data
dictionary. It is preferable to use domain declarations for storing the value of a
database table field. When you use a domain declaration, the type and length for
the declared variable are read from the data dictionary.
Variables of type enumerate or set must always be declared with a domain
declaration.
It is also possible to declare an array by using a domain. In that case the number
of elements must be set between the brackets, the length of the elements is
embedded in the data dictionary.
Examples
The following examples illustrate various domain declarations, and the
declaration of the same variables without domains.
DOMAIN declarations
DOMAIN tst_str10 tmp_str, | String of length 10
tmp_str_arr(100) | 100 strings of
| length 10
DOMAIN tst_long tmp_lng1, | A long number
tmp_lng2, | Another long number
tmp_lng_matr(5,2) | A matrix 5 x 2
DOMAIN tst_double tmp_dbl, | A floating point
tmp_dbl_arr(100) | 100 floating points
STRING declarations
#define LENG 10
STRING tmp_str(LENG), | String of length 10
tmp_str_arr(LENG*10,10) | 10 strings of length
| 100
LONG declarations
LONG tmp_lng1, | A long number
tmp_lng2, | Another long number
tmp_lng_matr(5,2) | A matrix 5 x 2
DOUBLE declarations
#define MAXLEN=1000
DOUBLE tmp_dbl, | A floating point
tmp_dbl_array(MAXLEN/10) | MAXLEN/10 floating
| points
Programming features
2-8
3GL programming language features
Arrays
You use arrays to store multiple variables of the same type within one data item.
Each variable can be referred to with the construction array_name(index).
For example, the first element in a one-dimensional array is array_name(1).
An array can have up to four dimensions. The dimension (and, in case of a string,
also the length) of an array must be stated in the declaration.
There are three types of arrays: long, double, and string.
Long arrays
You declare one-dimensional long arrays as follows:
LONG lng_array(5) | 1-dimensional array for 5 longs
The number in parentheses after the array name specifies the number of longs
that can be stored in the array.
You declare two-dimensional long arrays as follows:
LONG lng_array(2,4)
The first number after the array name indicates the number of dimensions in the
array. The second number indicates the number of longs that can be stored in
each dimension. The following diagram illustrates a two-dimensional array as a
matrix:
lng_array(1,1) = 3 lng_array(2,1) = 100
lng_array(1,2) = 4 lng_array(2,2) = 98
lng_array(1,3) = 56 lng_array(2,3) = 55
lng_array(1,4) = 78 lng_array(2,4) = 77
Double arrays
A double array differs from a long array only in that it is prefixed by the keyword
DOUBLE and the array elements must be filled with double values. You declare
a double array as follows:
DOUBLE dbl_array(5)
Programming features
2-9
3GL programming language features
String arrays
The declaration of string arrays differs from that for other array type in that the
first dimension contains the length of the strings to be stored in the array. For
example:
STRING str_arr(10,5) | 5 strings of length 10
STRING str_arr(10,5,5,5) | A 5 x 5 x 5 matrix of
| strings of length 10
When referencing a string array, the first dimension indicates the start position in
the string. The particular string to be accessed is indicated by the other
dimensions. It is possible to specify a length for the string to be retrieved by
using a semicolon [;] followed by the required length. If you omit the length, the
total length of the string is taken.
Programming features
2-10
3GL programming language features
In these examples, strg(n) refers to the entire array from position n onwards and
strg(n;x) refers to x positions starting at position n.
Programming features
2-11
3GL programming language features
String lengths
There are two lengths associated with a string: the maximum and the current
length. The maximum length is defined at declaration of the string and the
current length can vary, depending on the contents of the string.
If a string is declared as STRING strg(100), the maximum length of strg is 100.
If strg is filled as strg = "hello", the current length is 5. If strg is filled as strg(1) =
"hello", the current length is also is 100, as the remaining positions are filled with
spaces. When you specify a start position, the string is always filled out with
spaces.
If a string is declared as FIXED, the current length is always equal to the
maximum length, because the string is always filled up with spaces. Also, in the
case of multi-dimensional strings, the current length is always equal to the
maximum length.
Fixed variables
A string variable can be declared as fixed so that its current length always equals
the maximum length. For example:
STRING name(10) FIXED
name = "andrew" | the string is always filled up
| with spaces
Based variables
The BASED mechanism is applicable to strings or arrays of all possible types. It
determines that a variable will be based on another variable. For based variables,
no memory space is reserved when they are declared. At runtime they use the
same memory space as the variable on which they are based. So by using this
mechanism, the same section of memory can be accessed via different names.
You use the following construction to base one variable on another:
BASE var_1 AT var_2
In the case of a string, the based variable is always fixed. You must ensure that
the based variable always fits in the variable on which it is based. So it will be
safe to declare the basic variable as FIXED.
Programming features
2-12
3GL programming language features
Example
STRING a(10) FIXED
STRING b(5) BASED
BASE b AT a(3) | This indicates that the space
| occupied by b is the same as the
| space for a(3;5)
b(2;3) = "yes" | a(4;3) now also contains "yes"
a(1;8) = "12345678" | b now contains "34567"
Multibyte strings
A string variable can be declared as a multibyte string, in order to handle
multibyte or bidirectional characters. For example:
STRING mb_str(10,5) MB | 5 multibyte strings of 10
characters
Example
This multibyte string contains six characters. The fourth character is a TSS (that
is, multibyte) character containing 4 bytes. Note that all TSS characters are
prefixed with hex 9b.
Programming features
2-13
3GL programming language features
Bidirectional strings
Bidirectional functionality is necessary to support languages that read and write
from right to left– for example, Arabic and Hebrew. Bidirectional input is
supported only on fields of type multibyte string. A string is bidirectional when it
contains at least one bidirectional character. You can check whether a string
includes bidirectional characters by calling mb.hasbidi(). All strings, including
bidirectional, are stored in logic order – that is, the first typed character is the
leftmost one in the string. This means that all regular string handling functions
like pos(), and constructors like the semicolon [;], work correctly.
Special attention must be paid when concatenating or splitting strings. When
bidirectional and non-bidirectional strings are concatenated, one part must be
reversed.
Common variables
Unlike other variables, which can be used only within the program in which they
are declared, common variables can be used in more than one program. Only
string variables can be declared as COMMON.
Common variables are automatically based on a common memory part that can
be used by several programs. For this reason they must be declared as BASED.
The fact that they are common must be indicated with the reserved word
COMMON.
Programming features
2-14
3GL programming language features
Example
In program 1 and program 2, the same memory space is used for variables com_1
and com_2.
Within program 1:
STRING com_1(10) BASED, com_2(15) BASED
COMMON com_1, com_2
<functions which use com_1 and com_2>
Within program 2:
STRING com_1(10) BASED, com_2(15) BASED
COMMON com_1, com_2
<functions which use com_1 and com_2>
When a normal string is copied into another string, it is always copied up to the
first NULL character. If the target string is a fixed string, then it is filled up with
spaces from the NULL character to the end of the string. The copy action can
result from a normal assignment, from passing a string as a call by value
parameter to a function, or from the use of the import() and export() functions.
There is one exception to this rule. When the left or right side in an assignment is
a record buffer (rcd.<table name>), all bytes in the buffer will be copied.
Programming features
2-15
3GL programming language features
For example:
table tttadv999
strbuf = rcd.ttadv999 | NULL characters are copied
rcd.ttadv999 = strbuf | NULL characters are copied
strbuf2 = strbuf | NULL characters are NOT copied
In all other cases, if NULL characters are meaningful, use copy.mem(). This
copies NULL characters as well as ordinary characters.
Expressions with binary operators have the following form, where each operand
can be another expression, variable, or constant:
operand_1 operator operand_2
The available operators can be divided into four categories: arithmetic, relational,
logical, and control operators.
Class Operator Description
Arithmetic - negation
*/+- multiply/divide/add/subtract
\ remainder after division
& string concatenation
Relational = r EQ is equal to
<>or NE is not equal to
> or GT is greater than
< or LT is less than
>= or GE is equal to or greater than
<= or LE is equal to or less than
Logical AND, OR, NOT logical ‘and’, ‘or’ and negation
Control ?: question mark expression
Programming features
2-16
3GL programming language features
The question mark expression is a special type of expression. The syntax is:
<condition> ? <expr_1> : <expr_2>
For further information on the different operator types, see the following
sections.
Arithmetic operators
Arithmetic operators perform arithmetic operations on the operands. All
arithmetic operators, except string concatenation, must have operands of
numerical type. If one of the two operands is a double, the other is also converted
to double, and the result is also of double type. For example:
45/30 is equal to 1
| 45 and 30 are both LONG so the result is LONG
45/30.0 is equal to 1.5
| 30.0 is a DOUBLE so the result is a DOUBLE
Examples
LONG lng_1, lng_2
DOUBLE doub
STRING strg_1(16), strg_2(50), strg_3(10), strg_4(20)
Expression Result
lng_2 = 8\3 The variable lng_2 contains 2, which is the
remainder after dividing 8 by 3.
lng_1 = lng_2 + 3 The variable lng_1 now contains 5.
doub = lng_1 * 2.0 The variable lng_1 is multiplied by 2.0;
the result (10.0) is stored in doub.
Programming features
2-17
3GL programming language features
Relational operators
Relational operators compare two operands. If the condition (equal, greater than,
less than, and so on) is satisfied, the result becomes TRUE. If not, it becomes
FALSE.
Relational operators can be performed on values of every available type, but the
operands of one expression must be of the same type. One exception to that rule
is that longs can be compared to doubles.
In the case of strings, the ASCII values of the strings are compared on the basis
of the following rules:
n The comparison is made on the basis of the ASCII value of the strings,
starting at the leftmost character of each string.
n If two characters are not equal, the string with the lower character value is
considered to be smaller and the comparison is terminated.
n If both strings contain the same number of characters and the characters agree
in all cases, the strings are equal. If one string is shorter than the other, and
the corresponding characters are equal, the shorter string is considered to be
smaller than the other.
Logical operators
Logical operators perform logical operations on their operands. The operator
NOT is unary, so it has only one operand. The operands of logical operators can
be logical expressions, relational expressions, variables, or constants.
Programming features
2-18
3GL programming language features
Operator precedence
An expression can include a number of operators, variables, and constants. The
overall result is calculated in accordance with the rules of precedence described
here. For example, because multiplication has precedence over addition, the
result of the expression (3 + 4 * 5) is 23 and not 35.
The following table lists all operators in order of decreasing precedence.
Operators with high precedence are evaluated before operators with lower
precedence. Operators on the same line in the table have the same precedence. If
they occur in one expression, they are evaluated from left to right.
Operator Associativity
- (negation) right to left
*/\ left to right
& left to right
+ - (minus) left to right
= > < <> <= >= none
NOT right to left
AND left to right
OR left to right
?: right to left
Programming features
2-19
3GL programming language features
In case of doubt, always use parentheses. This makes the program easier to read.
NOTES n The operators NOT and - (negation) are unary, the others are binary.
n The relational operators are non-associative. This means that A <= B <= C is
not available. This should be A <= B AND B <= C.
Assignment Operator
You use the assignment operator [=] to store variables, constants, and the results
of expressions in a variable.
Examples (general)
LONG I, J, K(100), L(100)
STRING S(50), A, B(10)
DOUBLE AMOUNT
J = 4
AMOUNT = 123.45 * J
L(20) = 1001
S = "This is an example"
I = J | The contents of J are stored in
| variable I
L(2) = L(20) | Now L(2) is equal to L(20)
A = S(3;1) | The character ’i’ is placed in A
B(1;2) = S(6;2) | The word ’is’ is placed in the first
| two positions of B
K = L | The entire content of array L is
| copied to K
Except in the case of doubles and longs, both operators must be of the same type.
For doubles and longs, the following rules apply:
Left operator Right operator and conversion
long Can be integer or double. The result is converted to integer. In
case of double, the digits after the decimal point are truncated.
After truncation the value must be between -2147483648 and
2147483647.
double Result converted to double.
Programming features
2-20
3GL programming language features
Transfer of control
The Baan 3GL programming language supports several statements that change
the flow of control in a program. These enable control to be transferred either
conditionally or unconditionally to a specified point in the program.
You use the GOTO statement to transfer control unconditionally to a specified
point. You use the IF...THEN...ELSE statement or the ON CASE statement for
conditional transfer. These latter statements evaluate a specified condition and
transfer control if the condition is TRUE.
Both the GOTO statement and the label to which it refers must be within the
same function. You cannot transfer control to a label in another function.
Programming features
2-21
3GL programming language features
IF...THEN
This tests a condition. If the condition evaluates to TRUE, the statements
following the IF...THEN statement are executed. For example:
IF condition THEN
statement(s)
ENDIF
IF...THEN...ELSE
This tests a condition. If the condition evaluates to TRUE, the statements
following the IF...THEN statement are executed. If the condition evaluates to
FALSE, the statements following the ELSE statement are executed. For example:
IF condition THEN
statement(s)_1
ELSE
statement(s)_2
ENDIF
Examples
IF a > b THEN
b = b + 1
ENDIF
IF present AND found THEN
count = count + 1
do_something()
ENDIF
IF isspace(str1) THEN
message("String is empty")
ENDIF
IF a > b THEN
max_val = a
ELSE
max_val = b
ENDIF
Programming features
2-22
3GL programming language features
Long expressions
The expression after ON CASE is evaluated and compared with the various
CASE expressions that follow. All expressions in the case labels must be of type
LONG or STRING. When string expressions are used, the ASCII value of the
string is compared with the ON CASE expression.
Programming features
2-23
3GL programming language features
For example:
ON CASE weekday
CASE 1:
day = "Sunday"
BREAK
CASE 2:
day = "Monday"
BREAK
CASE 3:
day = "Tuesday"
BREAK
DEFAULT:
day = "other day"
ENDCASE
String expressions
The expression after ON CASE is evaluated and compared with the various
CASE expressions that follow. Normally, when the ON CASE expression is a
string expression, the CASE expressions are also strings. However, if the ON
CASE expression evaluates to a non-printable character – for example, ESC
(=27), this cannot be tested against a string constant. In this situation, the CASE
expressions can be integer constants that represent ASCII values. The ASCII
value of the ON CASE expression is then compared with the numeric values of
the CASE labels.
Programming features
2-24
3GL programming language features
For example:
ON CASE choice_char
CASE "A":
CASE "E":
abort()
CASE "N":
next_screen()
BREAK
CASE "P":
last_screen()
BREAK
CASE 27:
escape()
BREAK
DEFAULT:
message("unknown choice")
ENDCASE
Iterations
Iterative statements repeat the associated statements until a specified condition
becomes FALSE.
WHILE statement
This statement has the following form:
WHILE expression
statement(s)
ENDWHILE
The expression is evaluated. If the result is TRUE (that is, non-zero), the
statements between WHILE and ENDWHILE are executed. The process is then
repeated until the expression is FALSE (that is, zero). When the expression
evaluates to FALSE, control passes to the statement after ENDWHILE. For
example:
LONG counter
counter = 1
WHILE counter <= 10000
counter = counter + 1
ENDWHILE
Programming features
2-25
3GL programming language features
FOR statement
This statement has the following form:
FOR num_var = num_expr_1 TO num_expr_2 [STEP num_expr_3]
statement(s)
ENDFOR
Programming features
2-26
3GL programming language features
For example:
LONG numbers(100), i
FOR i = 1 TO 100
IF numbers(i) <= 0 THEN
CONTINUE | Next iteration
ENDIF
IF NOT process(numbers(i)) THEN
BREAK | Exit FOR statement
ENDIF
ENDFOR
The BREAK and CONTINUE commands can be very useful in a program, but
you should be take great care when using them.
Functions
In a program, a function performs a particular task that can be executed many
times, with different values. The syntax of a function is as follows (parts between
brackets [] are optional):
FUNCTION [ function_type ] function_name( [ arglist ] )
{
declaration of local variables
statement(s)
RETURN[( return_value )]
}
where arglist consists of one or more argument declarations with the following
syntax:
[REFERENCE / CONST] argument_type argument_name
When including more than one argument declaration, use commas [,] to separate
the declarations. Note that the key word REFERENCE can be replaced by REF.
Programming features
2-27
3GL programming language features
If you do not specify a type, the function is of type void by default. In functions
of type void, the return statement cannot have any argument. For example:
FUNCTION add_one() | this function is of type void
{
count = count + 1 | count is a global variable
RETURN
}
Local variables
Variables declared within a function block are local variables. They are
accessible only within the function in which they are declared.
Example
function void test()
{
long I | Local variable
for i =1 to 100 | Always to be initialized by user
....
endfor
return
}
Static variables
You can declare local variables as static variables. The value of a static variable
is saved at the end of the function and is used again the next time the function is
called. A static variable is automatically initialized at the start of the program.
Normal local variables are undefined at each function call, and are not initialized
at first call.
Programming features
2-28
3GL programming language features
Example 1
function test()
{
static long started
if (not started) then
started = true
| Actions to be performed only first time around.
endif
....
return
}
Example 2
function void spool( long id, ref string line() )
{
static long save_id
static long lfn
if ( save_id <> id ) then | Optimalization
lfn = read_new_lfn( id )
save_id = id
endif
seq.puts( line, lfn )
}
Programming features
2-29
3GL programming language features
Global variables
Variables declared outside any function block are global variables. You can use
them in all functions that occur after the variable declaration.
Example 1
function test()
{
return
}
long glob_var
function long dupl()
{
return( glob_var * 2 )
}
Example 2
long i
function void test()
{
long i
i = 10 | This is the local variable
| Nothing happens to the global variable ’i’
}
Programming features
2-30
3GL programming language features
External variables
An external variable is declared outside the function blocks. You can use them in
all functions that occur after the variable declaration, and also in other programs
(for example, forms, reports, and runtime expressions). It is possible to declare
external variables within a function block but this is not recommended.
If a local variable has the same name as an external variable, the local variable is
used within the function. The external variable is not affected.
Point of declaration Outside the functions. (Or within a function, but this
is not recommended.)
Syntax of declaration extern <type> name
Initialization At program start:
numeric set to 0
strings set to ""
Scope (validity and time) Valid anywhere in the source, throughout the
execution. Also valid outside the program – for
example, on forms/reports, in runtime expressions,
and by way of import() and export().
Example
extern long i
function void test()
{
i = 10 | This is the external variable
}
Programming features
2-31
3GL programming language features
Function arguments
The arguments of a function are the variables declared in the function header.
Arguments can be accessed only within the function.
Value arguments
A value argument gets its value at the time of the function call and has its own
memory space. For example:
FUNCTION long dupl(long val) | val is a value argument
{
RETURN( val * 2 )
}
FUNCTION MAIN()
{
message("%d", dupl(10))
| the argument val gets value 10
}
Reference arguments
Reference arguments must be declared in the function header with the keyword
REFERENCE or REF.
A reference argument has the same memory space as the variable used in the
function call. Consequently, all changes made to a reference argument within the
function block are also accessible after the function call in the variable used in
the function call. If a reference argument has array subscripts, these must be
empty in the declaration as the contents and size of the call variable is used.
Programming features
2-32
3GL programming language features
FUNCTION MAIN()
{
STRING line(100)
IF read_line(line) THEN
. . . .
ELSE
message("No present line")
ENDIF
. . . .
}
Example 2
This example uses a multi-dimensional array:
FUNCTION VOID fill_array ( REF LONG array(,) )
{
array(1,1) = 10
array(1,2) = 20
....
}
FUNCTION MAIN()
{
STRING a(5,10)
fill_array(a)
}
Programming features
2-33
3GL programming language features
Constant arguments
Constant arguments must be declared with the keyword CONST in the function
header. These are similar to reference arguments in that the same memory space
is used for the constant argument and the variable used in the function call.
However, with constant arguments, it is possible to use a string constant within
the function call. Consequently, the value of the argument after the function call
is not returned in the calling function.
You cannot change a constant argument within the function. Nor can you use a
constant argument as reference in another function call. Only strings with one
dimension can be used as constant arguments. The array subscript of the constant
argument must be empty in the declaration because the size of the constant is
used. For example:
FUNCTION print_mess( CONST STRING mesg() )
{
IF NOT isspace(mesg) THEN
message("Message: " & mesg)
ENDIF
}
FUNCTION MAIN()
{
.....
print_mess("This is a message")
.....
}
Programming features
2-34
3GL programming language features
Function prototypes
A function consists of three parts:
n Function prototype
n Function definition (function block)
n Function call
The function prototype must be exactly the same as the function header in the
function definition. The prototype of a function is not always necessary. For
example, it is not necessary in the following situations:
n if the function is of type void and has no arguments
n if the definition of the function occurs before any call of that function
In all other situations the prototype of the function must occur before the
function call. For example:
prototype
FUNCTION LONG compnr_check( LONG new_compnr )
function call
IF compnr_check( 999 ) THEN
. . . .
ELSE
mess("pcgen00016", 999)
| Comp. number %d not present
ENDIF
definition
FUNCTION LONG compnr_check( LONG new_compnr )
{
TABLE tpctst999
SELECT pctst999.*
FROM pctst999
WHERE pctst999.compnr = :new_compnr
ORDER BY pctst999.compnr
SELECTDO
compnr = pctst999.compnr
SELECTEMPTY
RETURN(FALSE)
ENDSELECT
RETURN(TRUE)
}
Programming features
2-35
3GL programming language features
Function calls
The call of a function must have the same number of arguments as declared in
the function header. Value arguments can be called using a constant or a
variable; reference arguments can only be called using a variable. If the called
function is not of type void, the function call must be assigned to a variable or
used as value argument in another function call.
It is possible to use recursive function calls. This means that in a function block a
call to the same function is used. However, this is currently implemented only for
functions without local variables and arguments. In other situations, the
following runtime message is generated: "Recursion not yet implemented".
Preprocessor
The bic6.2 compiler for 3GL program scripts has a built in preprocessor with the
following functions:
n include files
n macro definition
n object identifications
n pragma codes
n conditional compiling
All preprocessor directives starts with a ’#’. A preprocessor directive must be the
first word on a source line, possibly with leading spaces or tabs.
Include files
To include files, use one of the following statements:
#include "filename"
#include <filename>
Files included between ’<’ and ’>’ are searched for in the directory
’$BSE/include<rel.number>’. This directory is reserved for system headers and
cannot be used for applications. Normally a file specified between quotes is
searched for using the standard file redirection method.
Note that the preprocessor works only during compilation of a 3GL source, as the
standard generator std_gen6.2 does not have a preprocessor pass. So it is not
possible to use 4GL events in an included file.
Programming features
2-36
3GL programming language features
Example
Suppose the following entry occurs in $BSE/lib/fd.6.2<package_comb>:
ippmmm:/usr/bse/standard6.2
Macro definition
Use the following statement to define a macro:
#define macroname[(arguments)]
Defining macros
The macro names in the source are expanded to the macro definition. If a macro
definition does not fit on one line, it is possible to continue the definition on the
next line(s) by using the caret symbol ’^’ at the beginning of each line. It is
possible to use arguments in the macro. For example:
#define a(x, y, z) for i = x to y
^ z()
^ endfor | The definition
Macro definitions with the same name but with different numbers of arguments
are regarded as different. For example:
#define x definition without arguments
#define x() definition with 0 arguments
#define x(arg1) definition with 1 argument
#define x(arg1,arg2) definition with 2 arguments
#define x(...) definition with undefined
number of arguments
Note that there is a difference between a macro without arguments and a macro
with zero arguments. In the first case, you must use ’x’ in the program script to
call the macro. In the second case, you must use ’x()’ to call the macro.
Programming features
2-37
3GL programming language features
Undefining macros
The ’#undef’ statement causes the macro definition to be ignored. The number of
arguments in the ’#undef’ call must match the number of arguments in the
definition.
For example:
#define MAXLENGTH 1000
#define INCR 1
#define INCR(i) i=i+INCR
.....
#undef MAXLENGTH
#define INCR 2 | Redefines INCR
.....
#undef INCR(i)
An error occurs if you apply #undef to an unknown macro. To be sure that the
macro was defined, use the following construction:
#ifdef INCR | without arguments
#undef INCR(i)
#endif
| macro call
string buffer(100)
long l_val
double d_val
fillbuf(buffer, "%d. %s = %d %5.2f", 1, "Value",
^ l_val, d_val)
The macro definition can contain a number of arguments, but the ellipsis notation
must be the last argument.
Programming features
2-38
3GL programming language features
Token pasting
In the macro, you can enter a part of a variable as a macro argument. The symbol
’##’ is used to distinguish macro arguments and the rest of the macro. This is
omitted in the macro call. You can paste more macro arguments together as one
identifier. This principle is called token pasting. It is used to reuse parts of the
source code, where using functions is impossible or difficult.
Example 1
#define p(x) message("%d", var##x)
#define q(x,y) message("%d", x##y)
#define r(x,y,z) message("%d", x##y##z)
long var1a, var1b
p(1a) | becomes: message("%d", var1a)
p(1b) | becomes: message("%d", var1b)
q(var, 1a) | becomes: message("%d", var1a)
q(var, 1b) | becomes: message("%d", var1b)
r(var, 1, a) | becomes: message("%d", var1a)
r(var, 1, b) | becomes: message("%d", var1b)
Example 2
#define VRC(table,v,r,c)
^ tt##table##.vers = v
^ tt##table##.rele = r
^ tt##table##.cust = c
Object identifications
The compiler always places a default identification in an object, but you can
include you own if you wish. You can use the UNIX command what to write all
object lines that begin with ’@(#)’ on standard output.
The default identification has the following content:
#ident "@(#)<source name>, YY/MM/DD, [HH/MM], From
${logname}"
For example:
#ident "@(#)<progname>, YY/MM/DD [HH/MM], version, author"
Programming features
2-39
3GL programming language features
Pragma codes
Pragma codes represent compiler options. The following pragma codes are
available:
Example
#pragma warning This is not a fine solution !
Where-used list
In some cases the where-used list is not updated automatically. For example,
when a session code is entered but not expected:
message("ttadv2130m000")
or
bms.send("command", event, "ttaad3100m000", pr.id)
To put this session code into the where-used list, enter the following command
line:
#pragma used session ttadv2130m000
The following example illustrates the pragma codes to update the where-used
list:
#pragma used include <file>
#pragma used table <table code>
Programming features
2-40
3GL programming language features
Usually the where-used list is updated. In the case of functions, the where-used
list is updated if the function call contains the string value. For example:
mess("ttadvs0000", 1) | Where-used list will be updated
str = "ttadvs0000"
mess(str, 1) | Where-used list will not be
| updated
Conditional compiling
Directives
The preprocessor provides the following directives to enable you to compile
parts of the source depending on certain conditions:
#ifdef <macro> The source after #ifdef up to
#else/#elif/#endif is compiled if <macro>
is defined. Otherwise this source is
ignored.
Programming features
2-41
3GL programming language features
Programming features
2-42
3GL programming language features
These macros can also be used in the #if conditions. For example:
bic6.2 -DDEBUG -DMYTEST <source>
|source
#if DEBUG and MYTEST
message("Some debug information")
...
#endif
#if STANDARD
....
#elif ( CUSTOMER_X and (not CUSTOMER_Y) )
....
#endif
n You can use #ifdef to make a part of the file inactive. For example:
#ifdef OLD
....
....
....
#endif
n The preprocessor works only during compilation of a 3GL source, as the
standard generator std_gen6.2 does not have a preprocessor pass. So it is not
possible to use 4GL events in #if, #ifdef or #ifndef.
Programming features
2-43
3GL programming language features
For example:
message("This is at line %d in the source %s",
__LINE__, __FILE__)
Programming features
2-44
3GL programming language features
Compiler
You compile program scripts with the bic6.2 compiler. The compiler is
automatically activated after you have edited your program or report script and
after the use of std_gen6.2 and repgen6.2 at the option ’Compile’ in the data
dictionary. You can also use the compiler to compile 3GL programs
The syntax for the compiler is:
bic6.2 [-ilpsV] [-wW[level]] [-o <object>]
[-d dll[:dll...]] [-D <macro>] [-I <dir>] source
Programming features
2-45
3GL programming language features
The warnings associated with the various level numbers are as follows:
Level Warning
1 Declared but never used
For example, remove the declaration of the non-used variables.
Warnings related to an include file can be prevented by entering
"#pragma nowarnings" at the beginning of the include file. All
warnings caused by the include file will then be ignored.
2 Function never used
A function is found but never called. For instance remove the function.
This warning related to an include file can be prevented by entering
"#pragma nowarnings".
3 Return value of function ignored
When a function yields a value, that value must be checked. The reason
is that many functions return TRUE or FALSE, depending on whether
the action has been completed successfully or not. If the return value is
of no importance, a dummy value must be assigned to the function. For
example:
dummy = ittadv0037.search.label(....)
Programming features
2-46
3GL programming language features
function main()
{
domain tttst.db62 dbldom
double a, b
if a = b then
...
endif
if d() > a then
...
endif
if a <= dbldom then
...
endif
}
Programming features
2-47
3GL programming language features
function main()
{
a = 5
make.ten(a)
message("a = %d", a) | results in a = 10
}
Programming features
2-48
3GL programming language features
You can specify the options for automatic compilation in the session Maintain
Development Parameters (tadv0110m000).
When an error is found in the program, all warnings after that error are
suppressed.
Programming features
2-49
3GL programming language features
Programming features
2-50
3 4GL programming features
Overview
This section describes the 4GL features of the BAAN programming language.
When you create a session, the session generator generates a standard source.
This standard source provides default session functionality. If the required
functionality of the session is not fully implemented by the standard source, you
can program the additional functionality in a 4GL program script.
In previous versions of the software, changes or additions to the default
functionality for a session were programmed in a single script that was associated
with the session. Both user interface actions and database actions were
programmed in this script.
In BaanERP, user interface actions and database actions have been separated.
The Data Access Layer (DAL) now handles database interaction. Programmers
create a user interface (UI) script to change the default behavior of a session.
They create a DAL script to program all the logical integrity rules for a particular
table. This section discusses UI scripts.
Programming features
3-1
4GL programming features
Event-driven programming
4GL scripts are event oriented. They consist of one or more event sections in
which you program actions to be performed at particular states of execution of
the standard program – for example, when a session is started, before a form is
activated, before input to a field, after input to a field, and so on. It is not
necessary to program all sections, only those for which the standard program
does not provide the required functionality.
The statements programmed in a section can be a combination of 3GL/4GL
functions and 3GL statements. For information about the 3GL programming
language, see Chapter 2, 3GL programming language features.
Event sections
A 4GL script can contain one or more of the following types of sections:
n Program sections
n Form sections
n Group sections
n Choice sections
n Field sections
n Zoom sections
n Main table sections
With the exception of program sections, each section consists of a main section
and one or more subsections. A main section indicates the object for which the
programmed actions must be executed. A subsection specifies when the actions
must be executed. Program sections consist of a main section only.
If you do not include a main section immediately before a subsection, the
subsection is assigned to the previous main section in the script. For example:
form.1: | main section
init.form: | subsection executed for form 1
...
...
before.form: | subsection executed for form 1
...
...
after.form: | subsection executed for form 1
...
Programming features
3-2
4GL programming features
Program sections
You use program sections to define functions, and to declare tables and global
variables, that you want to use in the other sections in the script. You also use
program sections to program actions that you want to be executed when the
session starts or ends.
The following program sections are available. They are all main sections. There
are no subsections associated with program sections.
Main sections
declaration:
Use this section to declare tables and global variables that you want to use in
other sections in the script. See, “Declarations” and “Tables” in Chapter 2 for
details of the declaration syntax. You also use this section to define function
prototypes.
before.program:
Use this section to program actions that must be executed when the session starts.
For example, you can use this section to initialize or import variables or to read a
special record. Note that the default values or imported values overwrite the
fields of the main table.
Programming features
3-3
4GL programming features
on.error:
Use this section to program actions that must be executed at the end of the
session, before the after.program section. If the session is canceled, the actions
in this section are not executed. If an error is detected, you can check the
predefined variable e for the error code.
after.program:
Use this section to program actions that must be executed at the end of the
session, after the on.error section. If the session is canceled (with the command
ABORT.PROGRAM), the actions in this section are not executed.
after.update.db.commit:
Use this section to program actions that must be executed immediately after a
commit.transaction() call, if the database is updated.
before.display.object:
Use this section to program actions that must be executed each time the entire
record is displayed.
functions:
Use this section to define the functions used in the other sections. This must be
the last section in the script. The function syntax is the same as for 3GL
functions.
Programming features
3-4
4GL programming features
Example
declaration:
table tpctst999
long var01, ret
before.program:
if read_parameter() then
mess("pctsts0001", 1) | Parameter not present
stop()
endif
on.error:
mess("........", 1)
functions:
function long read_parameter()
{
select pctst999.*
from pctst999
order by pctst999._index1
as set with 1 rows
selectdo
return(0)
selectempty
return(1)
endselect
}
Form sections
You use form sections to program actions that you want to be executed when
forms are activated or ended. Form sections consist of a main section and a
subsection. The main section specifies the particular form(s) for which the
actions are to be executed. The subsections specify when the actions must be
executed – for example, when the form is activated or when the form is ended.
Main sections
form.<form number>:
The subsections associated with this section are executed for the specified form.
The <form number> is the sequence number of the form, as defined in the
Maintain Sessions by Package VRC session (ttadv2100m000).
Programming features
3-5
4GL programming features
form.all:
The subsections associated with this section are executed for all forms of the
session.
form.other:
A subsection associated with this section is executed for all forms for which the
particular subsection has not been programmed in a form.<form number>
section.
Subsections
init.form:
The actions programmed in this subsection are executed the first time the
specified form becomes current, immediately before the subsection before.form.
You use this subsection to program the first action to be performed by the system
– a first.set or first.view, for example.
before.form:
The actions programmed in this subsection are executed each time the specified
form becomes current.
after.form:
The actions programmed in this subsection are executed each time the specified
form is ended.
Example:
form.1:
init.form:
execute(first.set)
form.other:
init.form:
display("disp3")
form.all:
before.form:
display("disp")
Note:
Only the form.all section is relevant to dynamic forms. For dynamic forms, use
the group sections instead.
Programming features
3-6
4GL programming features
Group sections
With dynamic forms, the mapping of groups to forms is not fixed. Consequently,
the only form section that is relevant to dynamic forms is the form.all section.
When dealing with dynamic forms, you use group sections instead of form
sections
You use group sections to program actions that you want to be executed when
particular groups are activated or ended. Group sections consist of a main section
and a subsection. The main section specifies the particular group(s) for which the
actions are to be executed. The subsections specify when the actions must be
executed – for example, when the group is activated or when the group is ended.
Note that a group becomes active when the form on which it occurs becomes
current.
Main section
group.<group number>:
This section defines the group for which the actions programmed in the group
subsections are executed. The group number is automatically generated when the
group is created.
Subsections
init.group:
The actions programmed in this subsection are executed only the first time the
group becomes active, immediately before the before.group subsection. You use
this subsection to program the first action to be performed by the system when
the group becomes active. When the group is split across two or more forms
(because not all the group fits on one form or because it is a repeating group),
this subsection is executed the first time that the first form on which the group
occurs becomes current.
Note: the init.group section for group.1 is the former init.form section for
form.1. Group number 1 is not one of the groups in the form-definition.
before.group:
The actions programmed in this subsection are executed each time the specified
group becomes active. When the group is split across more than one form, this
subsection is executed whenever any form on which it occurs becomes current.
Programming features
3-7
4GL programming features
after.group:
The actions programmed in this subsection are executed each time the form on
which the group occurs is ended. When the group is split across more than one
form, this section is executed whenever any form on which the group occurs is
ended.
Choice sections
You use choice sections to program actions that you want to be executed when
standard commands are activated or ended. Choice sections consist of a main
section and a subsection. The main section specifies the standard command for
which the actions must be executed. The subsections specify when the actions
must be executed.
Main section
choice.<standard command>:
The subsections associated with this main section are executed for the specified
standard command. You use the Maintain Forms by Package VRC session to
select the standard commands (ttadv3100m000) for each form. A list of standard
commands appears at the end of this help topic.
Subsections
before.choice:
The actions programmed in this subsection are executed immediately before the
specified command is executed. You can use this subsection, for example, to test
data before the command process continues. You can use the choice.again()
function to stop the command.
on.choice:
The actions programmed in this subsection are executed when the specified
command is activated. These actions are executed instead of the standard action
associated with the command.
Programming features
3-8
4GL programming features
after.choice:
The actions programmed in this subsection are executed immediately after the
specified command has been executed. This subsection is not available for the
end.program and abort.program commands. For example:
choice.first.view:
after.choice:
execute(first.set)
Standard commands
The following table lists the available standard commands and the types of
program in which the various choice subsections can be programmed for each
command.
No Choice_option Description Before On After
01 start.set Add/start a new group in 1234 ---4 1234
main table
02 first.view View first group of main 1234 ---4 1234
table
03 next.view View next group of main 1234 ---4 1234
table
04 prev.view View previous group of 1234 ---4 1234
main table
05 last.view View last group of main 1234 ---4 1234
table
06 def.find Find a specific record on 1234 ---4 1234
key
Programming features
3-9
4GL programming features
Programming features
3-10
4GL programming features
Programming features
3-11
4GL programming features
Programming features
3-12
4GL programming features
Field sections
You use field sections to program actions that you want to be executed for a
variety of field events. Field sections consist of a main section and a subsection.
The main section specifies the field(s) for which the actions must be executed.
The subsections specify when the actions must be executed.
Main sections
field.<field name>:
The subsections associated with this main section are executed for the specified
field. The field name you specify must correspond with the name on the form.
field.all:
The subsections associated with this main section are executed for all fields on
the form
field.other:
A subsection associated with this section is executed for all fields for which the
particular subsection has not been programmed in a field.<field name> section.
Subsections
init.field:
The actions programmed in this subsection are executed the first time that the
form on which the field occurs becomes current. The subsection is executed
immediately before the init.form section of the form. You can use this section to
change field attributes.
before.field:
The actions programmed in this subsection are executed each time the focus
moves to the specified field. The subsection is executed immediately before the
before.input or before.display subsections.
before.input:
The actions programmed in this subsection are executed immediately before
input to an input field commences. This section is supported for backward
compatibility only. In BaanERP programs, use enable.fields() and
disable.fields() to enable and disable fields.
Programming features
3-13
4GL programming features
before.display:
The actions programmed in this subsection are executed each time that the
specified field is displayed. You can use this subsection, for example, to set the
value of a display field or to change the output format of currencies and dates (by
using attr.oformat$).
before.zoom:
When a zoom process is started on the specified field, the actions programmed in
this subsection are executed immediately before the zoom process is executed.
You can use this subsection to change the zoom attributes. For example, in the
field definition in the form manager, a default zoom code can be specified. You
can then use this subsection to change the zoom code (by setting the predefined
variable attr.zoomcode).
before.checks:
The actions programmed in this subsection are executed after input to the field
has been completed and the TAB key has been pressed. The subsection is
executed immediately before the domain and references are checked. You can
use this section, for example, to change the value of the field before the domain
and reference checks.
domain.error:
The actions programmed in this subsection are executed if the domain check
causes an error after data has been entered in the field. You can use this section
to provide your own error message instead of the standard message.
ref.input:
The actions programmed in this subsection are executed if a reference error
occurs. If you program this section, the standard program does not display a
message.
ref.display:
The actions programmed in this subsection are executed if there is an error in the
reference display.
Programming features
3-14
4GL programming features
check.input:
The actions programmed in this subsection are executed immediately after the
domain and reference checks. You can use this section to test for errors that are
not detected automatically. If the standard program detects an error, input is
automatically restarted. In a script, you can use set.input.error() to display an
error message and start input again.
This section is replaced by DAL functionality (if a DAL exists for the table).
on.input:
The actions programmed in this subsection are executed immediately after the
check.input subsection. You can use this section, for example, to perform some
appropriate action when the user enters a special character or to display a
warning message in certain cases.
when.field.changes:
The actions programmed in this subsection are executed when the new value
entered in the specified field differs from the old value.
after.zoom:
The actions programmed in this subsection are executed when the zoom process
on a specified field ends. You can use this subsection, for example, to redisplay
any field that has changed as a result of the zoom process.
after.input:
The actions programmed in this subsection are executed after all checks have
been performed on input to the specified field and after the when.field.changes
subsection has been executed. In this subsection, you can use the to.field()
function if the sequence deviates from the default.
after.display:
The actions programmed in this subsection are executed just after display of the
specified field. You can use this subsection, for example, to read reference tables.
Programming features
3-15
4GL programming features
after.field:
This is the last subsection for a field. The actions programmed in this subsection
are executed after input to or display of the specified field. This section is always
executed, even if the user left the field by pressing ESC, one of the arrow keys,
or a mouse button. You can use this subsection to perform special actions before
leaving the field.
Example
field.pctst099.item:
check.input:
select pctst001.*
from pctst001
where pctst001.item = :pctst099.item
as set with 1 rows
selectdo
....
selectempty
pctst001.dsca = "*****"
set.input.error(".....")
endselect
before.input:
if ..... then
attr.input = false
endif
after.display:
select pctst001.*
from pctst001
where pctst001.item = :pctst099.item
as set with 1 rows
selectempty
pctst001.dsca = "*****"
endselect
field.pctst099.date:
before.input:
attr.oformat$ = "%D002,2"
Programming features
3-16
4GL programming features
Zoom.from sections
You use zoom.from sections to program actions that you want to be executed
when the current session is activated as a zoom process. A zoom process can be
activated by a form-specific command of type session, by zooming on an input
field, by pressing CTRL+B, or by calling zoom.to$() in the program script.
Zoom.from sections consist of a main section and a subsection. The main section
specifies the process for which the actions must be executed. The subsections
specify when the actions must be executed.
Main sections
zoom.from.<zoom name>:
Each field has a name that can be used as a zoom name. You can specify the
zoom name in this main section. The zoom name indicates which field the
current session was zoomed from (when the subprocess is started from a form
command, the zoom name is "choice"). The subsections associated with this
main section are executed when the current process was zoomed to from the
specified process.
zoom.from.all:
The subsections associated with this main section are executed for all processes
from which the current session can be zoomed to.
zoom.from.other:
A subsection associated with this section is executed for all processes for which
the particular subsection has not been programmed in a zoom.from.<zoom
name> section.
Subsections
on.entry:
The actions programmed in this subsection are executed each time the current
process is started from the specified process(es). You can use this subsection to
import variables.
Programming features
3-17
4GL programming features
on.exit:
The actions programmed in this subsection are executed at the end of the current
process, if the current process was started from the process(es) specified in the
main section. You can use this subsection to export variables.
Example
zoom.from.all:
on.entry:
import("globvar", localvar)
on.exit:
export("globvar", localvar)
Main section
main.table.io:
The subsections associated with this main section are executed either before or
after input to or output from the main table. The main table for the current
session is defined in the data dictionary.
Subsections
before.read:
The actions programmed in this subsection are executed immediately before each
read action on the main table.
Programming features
3-18
4GL programming features
after.read:
The actions programmed in this subsection are executed after each read action on
the main table. You can use this subsection to call skip.io() in order to skip the
record just read and to read the next record (if necessary).
before.write:
The actions programmed in this subsection are executed before each write action
on the main table. A write action occurs when a record is inserted. You can use
this subsection to call skip.io() in order to undo the write action.
after.write:
The actions programmed in this subsection are executed after each write action
on the main table. A write action occurs when a record is inserted. You can use
this subsection, for example, to write data to tables other than the main table.
after.skip.write:
The actions programmed in this subsection are executed if a write action on the
main table has been skipped as a result of actions programmed in the
before.write subsection. The actions are executed immediately after the skip
action.
before.rewrite:
The actions programmed in this subsection are executed immediately before each
rewrite of a record in the main table. A rewrite action occurs when a record is
changed. You can use this subsection to call skip.io() in order to skip the rewrite
action.
after.rewrite:
The actions programmed in this subsection are executed after each rewrite action
on the main table. A rewrite action occurs when a record is changed.
after.skip.rewrite:
The actions programmed in this subsection are executed if a rewrite action on the
main table has been skipped as a result of actions programmed in the
before.rewrite subsection. The actions are executed immediately after the skip
action.
Programming features
3-19
4GL programming features
before.delete:
The actions programmed in this subsection are executed immediately before each
delete action on the main table. You can use this section to call skip.io() in order
to skip the delete action.
after.delete:
The actions programmed in this subsection are executed immediately after each
delete action on the main table. You can use this subsection, for example, for
deleting references, if this is not done automatically.
after.skip.delete:
The actions programmed in this subsection are executed if a delete action on the
main table has been skipped as a result of actions programmed in the
before.delete subsection. The actions are executed immediately after the skip
action.
read.view:
The actions programmed in this subsection are executed immediately after a
view action on the main table (start.set, first.view, next.view, prev.view or
last.view). You can use this subsection to call skip.io() in order to skip an entire
set of records with the same value in the view fields.
Example
main.table.io:
before.delete:
if (not pctst099.del) then
skip.io("pctsts0001")
| cannot be deleted
endif
read.view:
if strip$(pctst099.cprj) = "" then
skip.io("")
endif
Programming features
3-20
4GL programming features
Main routine
The main routine displays the first form on the screen and waits for a command.
function main()
{
before.program
read.form()
init.references
create.sql.queries
if background then
get.ref.var(parent)
read record
endif
db.bind(tmain) | Not in type 4
if job.process then | Only type 4
before.choice.run.job
execute(cont.process) or on.choice.run.job
after.choice.run.job
execute(end.program)
endif
zoom.from.on.entry
for each field on form
init.field
put.attributes()
endfor
change to start index | Not in type 4
init.form
execute start event
before.form
while true
input.choice()
if update.status and choice <> ... then | Not in
| type 4
on.update.db()
| See "update database" section
endif
on case choice
case <choice.option>
before.<choice.option>
on.<choice.option>
after.<choice.option>
break
Programming features
3-21
4GL programming features
case ...
....
endcase
endwhile
Choice sections
The choice sections above are given as before.choice.option and
after.choice.option. In a 4GL program, a choice section consists of the main
section choice.choice.option and one of the subsections before.choice, on.choice,
or after.choice.
Form sections
When changing from form X to form Y, the form sections are executed in the
following sequence:
after.form for X
init.form for Y (only the first time)
before.form for Y
The above subsections can be defined, as follows:
for all forms : form.all
for a specific form : form.<form name>
for forms not specifically defined : form.other
At init.form the sequence is:
form.all: init.form
form.<form name>: init.form or form.other: init.form
Programming features
3-22
4GL programming features
Field sections
There are two groups of field sections:
n sections for which the field.all section is executed first:
init.field
before.field
before.input
before.display
before.checks
before.zoom
check.input | if not in DAL
on.input
n sections for which field.all is executed after field.<field name> or field.other:
after.input
after.display
after.zoom
ref.input
ref.display
domain.error
when.field.changes
after.field
The general flow of input fields is as follows:
Field.input:
before.field
if not input.field then
read.reference
if error.reference then
ref.display
else
before.display
display.field()
after.display
endif
Programming features
3-23
4GL programming features
return
endif
before.input
if input disabled then
read.reference
if error.reference then
ref.display
else
before.display
display.field()
after.display
endif
return
endif
zoom.ret:
do.input.field()
if in.ret = ZOOM then
before.zoom
zoom.to ...
after.zoom
goto zoom.ret
endif
if choice = f.to.choice or
in.ret = arrow.up/down/left/right/tab then
goto after.field
endif
before.checks
check.domain()
if domain.error then
domain.error
error.message
goto field.input
endif
check.reference
if reference.error then
ref.input
error.message
goto field.input
endif
check.input
if check.input.error then
error.message
goto field.input
endif
on.input
....
....
Programming features
3-24
4GL programming features
when.field.changes
after.input
after.field
End of program
The flow of the end of the program is as follows. The function end.of.program()
is called when executing the standard command END.PROGRAM.
function end.of.program()
{
before.end.program
if e then
on.error
endif
after.form
after.program
if zoomfield <> "" then
fill.zoomreturn
zoom.from.on.exit
if record.marked then
commit.transaction() | Not in type 4
exit(exit.val)
endif
endif
commit.transaction() | Not in type 4
exit()
}
Zoom sections
The zoom.from.on.entry and zoom.from.on.exit sections are used In the main
routine and in the end.of.program() function. In a 4GL program, a zoom section
consists of a main section (zoom.from.all, zoom.from.<zoomname>, or
zoom.from.other) and a subsection (on.entry or on.exit).
The sequences in which the sections are executed differ for on.entry and on.exit.
For on.entry, zoom.from.all is executed first and then zoom.from.<zoomname>
or zoom.from.other. For on exit, it is the other way around.
Update database
An update of the database is necessary if a record is added, changed or deleted.
The actual update is executed if one of the following actions is activated after a
record has been added, changed or deleted: start.set, def.find, find.data, first.set,
next.set, prev.set, last.set, next.help, prev.halfset, change.order, cont.process.
Programming features
3-25
4GL programming features
Programming features
3-26
4GL programming features
Case 1
From the main process with main table X you have zoomed to the subprocess
with main table Y. Table X has a foreign (cross-reference) key to table Y. For
example, X = customer table, Y = currency table. The currency field in the
customer table refers to the currency table.
The standard program imports the field(s) from table X and stores them in the
primary key fields of table Y.
There is no need to adjust the main session in order to import the variables into
the subsession.
Case 2
From the main process with main table X, you have zoomed to the subprocess
with main table Y. A field in table Y refers to table X. (In most cases, there is an
identifying relationship between table X and table Y – for example, order header
(table X) and order lines (table Y).) The standard program imports the primary
key values from table X and stores them in the corresponding fields of table Y.
Programming features
3-27
4GL programming features
Example
Primary key of table X is Order number; primary key of table Y is Order number,
position number.
The standard program imports the order number from table X to the
corresponding field in table Y. The position number in table Y remains, of
course, empty.
Case 3
From the main process with main table X, you have zoomed to the subprocess
with the same main table. (For example, a zoom from ’Maintain Item Data’ (type
1) to ’Display Item Data’ (type 2 or 3).)
The standard program imports the primary key value from table X for the main
process and stores it in the primary key fields of table X for the subprocess.
Case 4
From the main process with main table X you have zoomed to a subprocess
without a main table (for example, a print program). The standard program
imports the primary key values of main table X for the main process and stores
them in the primary key fields of table X (if available) for the subprocess.
Example
A zoom from ’Maintain Item Data’ to ’Print Item Data’. The main table for the
main process is tstpi100. The subprocess imports values of tstpi100.cuno and
tstpi100.item from the main process and stores them in the fields of the
subprocess.
Programming features
3-28
4GL programming features
Case 5
From the main process without a main table you have zoomed to a subprocess
with main table X. The standard program imports the primary key values of table
X (if available) for the main process and stores them in the primary key fields of
the subprocess’s main table.
Example
A zoom from ’Print Item Data’ to ’Display Item Data’. The main table for the
subprocess is ttstpi100. The standard program tries to import tstpi100.cuno and
tstpi100.item from the main process and stores them in the fields of the main
table for the subprocess.
Example
field.item.t:
before.zoom:
tstpi100.cuno = cuno.f
tstpi100.item = item.f
Case 6
From the main process with table X you have zoomed to a subprocess with table
Y. There is no relationship between table X and table Y (none has been defined
in the data dictionary). The standard program imports the primary key values of
table Y for the main process (if available) and stores them in the primary key
fields of table Y for the subprocess.
Programming features
3-29
4GL programming features
Example
field.tswoc150.item:
before.zoom:
tstpi100.cuno = tswoc100.cuno
tstpi100.item = tswoc150.item
Programming features
3-30
4 Report scripts
Overview
BaanERP reports are used to output data from the database to a variety of devices
(for example, printers, displays, and files).
The contents and layouts of reports are defined in the data dictionary. In addition,
you can link a report script to a report. In a report script, you can program actions
that you want to be performed at particular stages of the report execution. For
example, you can create a script to perform calculations on the report data or to
read records from related tables that are not automatically available to the report.
You program report scripts in the same way as you program 4GL program
scripts, except that report scripts use different event sections and some special
functions.
Event sections
A report script consists of one or more event sections in which you program
actions to be performed at particular states of execution of the report to which the
report script is linked. The statements programmed in a report script section
consist of a combination of 3GL language statements and report script functions.
Report scripts support the following event sections:
n program sections
n report sections
n text field sections
Program sections
You use program sections to define functions, and to declare tables and global
variables, that you want to use in the other sections in the script. You also use
program sections to program actions that you want executed at the start and end
of the report and after the report writer receives a record.
The following program sections are available. They are all main sections. There
are no subsections associated with program sections.
Programming features
4-1
Report scripts
declaration:
Use this section to declare tables and global variables that you want to use in
other sections in the report script. See “Declarations” and “Tables” in Chapter 2
for details of the declaration syntax. Note that there is no need to declare a table
if a field of that table is defined in the report writer as an input field. The report
writer declares such tables automatically.
before.program:
Use this section to program actions that must be executed when the report is
started. For example, you can use this section to initialize or import variables.
after.program:
Use this section to program actions that must be executed at the end of the report.
For example, you can use this section to close files that were opened during
execution of the report.
after.receive.data:
Use this section to program actions that must be executed whenever the report
writer receives a record. For example, you can use this section to read or modify
a variable.
functions:
Use this section to define functions that you want to use in other sections in the
report script. The syntax of functions used in a report script is the same as for
3GL functions.
When included, this section must be the last section in the report script.
Report sections
A report consists of a number of layouts, which define the content and
organization of the various parts of a report (for example, the header, footer, and
body of the report). There are a number of possible layout types, as follows:
n before.report – printed once at beginning of the report (a title page, for
example)
n after.report – printed once at the end of the report
n header – printed at the top of each page
Programming features
4-2
Report scripts
Main sections
before.report.<layout_number>:
Actions programmed in this section are executed for a specified layout of type
before.report.
after.report.<layout_number>:
Actions programmed in this section are executed for a specified layout of type
after.report.
header.<layout_number>:
Actions programmed in this section are executed for a specified layout of type
header.
detail.<layout_number>:
Actions programmed in this section are executed for a specified layout of type
detail.
before.<field name>.<layout_number>:
Actions programmed in this section are executed for a specified layout of type
before.field.
Programming features
4-3
Report scripts
after.<field name>.<layout_number>:
Actions programmed in this section are executed for a specified layout of type
after.field.
footer.<layout_number>:
Actions programmed in this section are executed for a specified layout of type
footer.
Subsections
before.layout:
Actions programmed in this subsection are executed before the specified layout
is printed.
When lattr.print is set to false, the layout is not printed and the before.layout
and after.layout sections are not executed. If you set lattr.print to false in the
before.layout section itself, the layout is not printed and the after.layout section
is not executed.
after.layout:
Actions programmed in this subsection are executed after the specified layout is
printed.
Programming features
4-4
Report scripts
Main section
field.<text_field>:
Actions programmed in this section are executed for all instances of the specified
text field that are included in the report. The text field must have been defined as
a report input field in the data dictionary.
Subsection
before.print:
Actions programmed in this section are executed before the specified text field is
printed.
Predefined variables
You can use the following predefined variables in a report script.
R = read-only R/W = read and write
Programming features
4-5
Report scripts
Programming features
4-6
Report scripts
You cannot use need(), page(), skip(), skip.to(), or to.page() in header and
footer layouts.
Programming features
4-7
Report scripts
Syntax
The following is the syntax for variables and expressions included in text lines:
$variable or #variable
${expression} or #{expression}
When the $ symbol if used, the text moves over to accommodate the expanded
variable or expression. When the # symbol is used, the expanded variable or
expression overwrites existing text.
Example
The following is an example of text created by using the text manager. The text
includes both variables and expressions that can be expanded/substituted for
report purposes.
To: $surname $christian name #date , Ede
$address
$ZIP code $city
Dear $christian name:
We have the pleasure of informing you that, as of $date,
your salary has been raised by 5%. For you this implies
a gross amount of
${edit( salary + ( salary * 0.05 ), "ZZZZ9,ZZ" )} per
month.
Kind regards, $Mgr.
Programming features
4-8
5 Database handling
Overview
BaanERP data is stored in a relational database, which is managed by a
Relational Database Management System (RDBMS). The RDBMS acts as the
database server for BaanERP applications. BaanERP supports the following
RDBMS products:
n Informix
n Oracle
n Sybase
n DB2
n Microsoft SQL Server
The BaanERP architecture includes a database driver. This provides the
application server (that is, the bshell) with a common interface to the database
server, regardless of which RDBMS product is used. This enables the application
server to be database independent. The database driver is responsible for
translating database commands received from the application server into
RDBMS-specific commands. Although, the database driver’s interface with the
application server is the same for all RDBMS products, Its interface with the
RDBMS is RDBMS-specific. Therefore, there is a separate database driver for
each of the supported RDBMS products.
Programming features
5-1
Database handling
Database tables
A relational database presents information to the user in the form of tables. In a
table, data is organized in columns and rows. Each column (also referred to as a
field) represents a category of data. Each row (also referred to as a record)
represents a unique instance of data for the categories defined by the columns.
A field always refers to a domain, which defines a set of values from which one
or more fields can draw their actual values. For example, the ’tcweek’ domain is
the set of all integers greater than zero and less than or equal to 53.
Primary keys
Every database table has a field, or a combination of fields, which uniquely
identify each record in the table. This unique identifier is referred to as the
primary key. Primary keys are fundamental to database operations, as they
provide the only record-level addressing mechanism in the relational model.
Primary keys act as references to the records in a table.
Relationships/references
With a relational database, you can store data across multiple tables and you can
define relationships between the tables. This means that individual tables can be
kept small and data redundancy can be minimized. A relationship exists between
two tables when they have one or more fields in common. So, for example, a
Customer Details table can be linked to an Orders table by including a Customer
ID field in both tables. In the Customer Details table, the Customer ID field is the
primary key. In the Orders table, it is referred to as a foreign key. By linking the
two tables in this way, there is no need for the Orders table to include customer
details such as name and address. Note that references from one table to another
must always use the primary key.
Programming features
5-2
Database handling
Combined fields
A combined field is a field that consists of two or more child fields. You can use
combined fields as primary keys, and you can also use them for references and
indexes.
Indexes
Indexes facilitate speedy searching and sorting of database tables. An index is a
special kind of file (or part of a file) in which each entry consists of two values, a
data value and a pointer. The data value is a value for some field in the indexed
table. The pointer identifies the record that contains this value in the particular
field. This is analogous to a conventional book index, where the index consists of
entries with pointers (the page numbers) that facilitate the retrieval of
information from the body of the book.
Note that it is also possible to construct an index based on the values of a
combination of two or more fields.
Every table must have at least one index, which is an index on the primary key
field(s). This is referred to as the primary index. An index on any other field(s) is
referred to as a secondary index.
Programming features
5-3
Database handling
Naming conventions
The naming syntax for tables, record buffers, and table fields is as follows:
tppmmmxxx | table
rcd.tppmmmxxx | record buffer of table
ppmmmxxx.ffffffff | logical field of table
where t stands for table, pp is the package code, mmm is the module code, xxx is
the table number (range 000 to 999), and ffffffff is a field name (maximum 8
alphanumeric characters, starting with an alphabetic character).
Declaration of a table implies declaration of all its fields and its record buffer. It
is not necessary to declare these separately.
There are no special functions for opening and closing tables. A table is
automatically opened at the first database call on that table and it is automatically
closed at the end of the program.
You can use the record buffer of a table to save the contents of a record in a
temporary string. And you can subsequently restore the record from the buffer. If
a record contains numeric fields, you can only save and restore records. You
cannot perform any other actions on the temporary string, as the presence of
NULL characters will cause loss of data.
Data types
The data type is the internal representation of table field and domain data. The
following data types are available:
DB.BITSET DB.INTEGER
DB.BYTE DB.LONG
DB.COMBINED DB.MAIL
DB.DATE DB.MULTIBYTE
DB.DOUBLE DB.STRING
DB.ENUM DB.TEXT
DB.FLOAT DB.TIME
Programming features
5-4
Database handling
Transaction handling
With respect to database actions, a transaction is a sequence of related actions
that are treated as a unit. The actions that make up a transaction are processed in
their entirety, or not at all.
A transaction ends with the function commit.transaction() (all changes made
during the transaction are stored in the database) or with the function
abort.transaction() (no changes are stored in the database). A transaction starts
either at the beginning of a process, with the function
set.transaction.readonly(), with the function db.lock.table(), or after the
preceding transaction has ended.
A transaction is automatically rolled back (that is, it is undone) when a process is
canceled and if a program ends without a commit.transaction() or
abort.transaction() after the last database call. Undoing a transaction is only
possible if the underlying database system supports this.
Certain database actions cannot be placed within a transaction, because they
cannot be rolled back. These actions are: db.create.table(), db.drop.table(), and
set.transaction.readonly(). These functions can be called only at the start of a
program or after the end of the preceding transaction.
You can set a retry point immediately before a transaction. In case of an error,
the system returns to this point and re-executes the transaction from there.
A read-only transaction is a transaction in which you are permitted only to read
records (without lock) from the database. You retain read consistency during the
entire transaction. This means that during the transaction your view of the
database does not change, even if other users update the records. A read-only
transaction starts with the function set.transaction.readonly() (this must be
called after ending the preceding transaction or at the beginning of the program)
and ends with a commit.transaction() or abort.transaction(). A consistent view
consumes a large amount of memory, so a read-only transaction must be as short
as possible; user interaction during the transaction is not recommended.
Locking
Database inconsistencies can arise when two or more processes attempt to update
or delete the same record or table. Read inconsistencies can arise when changes
made during a transaction are visible to other processes before the transaction has
been completed – for example, the transaction might subsequently be abandoned.
Programming features
5-5
Database handling
Record/page locking
To ensure that only one process at a time can modify a record, the database
driver locks the record when the first process attempts to modify it. Other
processes cannot then update or delete the record until the lock has been released.
However, they can still read the record.
While one process is updating a table, it is important that other processes retain
read consistency on the table. Read consistency means that a process does not see
uncommitted changes. Updates become visible to other processes only when the
transaction has been closed. Some database systems do not support read
consistency, and so a dirty read is possible. A dirty read occurs when one process
updates a record and another process views the record before the modifications
have been committed. If the modifications are rolled back, the information read
by the second process becomes invalid.
Some databases, such as SYBASE, use page locking instead of record locking.
That is, they lock an entire page in a table instead of an individual record. A page
is a predefined block size (that is, number of bytes). The number of records
locked partly depends on the record size.
Supported features
INFORMIX ORACLE SYBASE DB2 SQL Server
locking row row page row page
dirty read yes no *
consistent read no yes *
transactions yes yes yes yes yes
* SYBASE will block when there is a read action (locked or not) on a record in a
page that has been locked.
Programming features
5-6
Database handling
Delayed locks
Locking a record for longer than required can result in unnecessarily long
waiting times. The use of delayed locks solves this problem to a great extent.
A delayed lock is applied to a record immediately before changes are committed
to the database and not earlier. When the record is initially read, it is temporarily
stored. Immediately before updating the database, the system reads the value of
the record again, this time placing a lock on it. If the record is already locked, the
system goes back to the retry point and retries the transaction. If the record is not
locked, the system compares the content of the record from the first read with the
content from the second read. If changes have been made to the record by
another process since the first read, the error EROWCHANGED is returned and
the transaction is undone. If no changes have occurred, the update is committed
to the database.
You place a delayed lock by adding the keyword FOR UPDATE to the SELECT
statement (see “BAAN SQL” later in this chapter).
For example:
table tpctst999
db.retry.point()
SELECT pctst999.*
FROM pctst999 FOR UPDATE
SELECTDO
pctst999.dsca = "...."
....
db.update(tpctst999, DB.RETRY)
ENDSELECT
Table locks
BaanERP provides a table locking mechanism, which enables you to lock all the
records in a specified table. A table lock prevents other processes from
modifying or locking records in the table but not from reading them. This is
useful when a particular transaction would otherwise require a large number of
record locks. You use the db.lock.table() function to apply a table lock.
Application locks
An application lock prevents other applications and users from reading and/or
modifying an application’s data during critical operations. It is not part of a
transaction and so is not automatically removed when a transaction is committed.
Instead, an application lock is removed when the application ends or when
appl.detete() is called.
Programming features
5-7
Database handling
Retry points
A retry point is a position in a program script to which the program returns if an
error occurs within a transaction. The transaction is then retried. There are a
number of situations where retry points are useful:
n During the time that a delayed lock is applied to a record/page, an error can
occur that causes the system to execute an abort.transaction(). In such cases,
all that BaanERP can do is inform the program that the transaction has been
aborted. However, if retry points are used, the system can automatically retry
the transaction without the user being aware of this.
n Some database systems generate an abort.transaction() when a dirty record
is read (that is, a record that has been changed but not yet committed). An
abort.transaction() may also be generated when two or more processes
simultaneously attempt to change, delete, or add the same record. In all these
situations, BaanERP Tools can conceal the problem from the user by using
retry points. It simply retries the transaction. If there is no retry point, the
transaction is aborted and the session is terminated.
n In BaanERP, updates are buffered, so the success or failure of an update is
not known until commit.transaction() is called. If an update fails, the
commit of the transaction also fails, and the entire transaction must be
repeated. If retry points are used, the system automatically retries the
transaction.
n Retry points can also resolve potential deadlock problems. If, for example,
the system is unable to lock a record, it rolls the transaction back and tries
again.
NOTE It is vital that retry points are included in all update programs.
The function db.retry.hit() returns 0 when the retry point is generated – that is,
the first time the code is executed. It returns a value unequal to 0 when the
system returns to the retry point through the database layer.
Programming features
5-8
Database handling
When the system goes back to a retry point, it clears the internal stack of
functions, local variables, and so on that were called during the transaction. The
program continues from where the retry point was generated. The value of global
variables is NOT reset.
When a commit fails, the database automatically returns to its state at the start of
the transaction; the program is set back to the last retry point. It is vital, therefore,
that the retry point is situated at the start of the transaction. The db.retry.hit()
call must follow the db.retry.point() call. Do not place it in the SQL loop itself
as this makes the code very untransparent. When a retry point is placed within a
transaction, the system produces a message and terminates the session.
Baan SQL
You use Baan SQL (Structured Query Language) to retrieve information from
the database. With Baan SQL’s SELECT statement, you can retrieve any
selection of data from the database, regardless of the number of tables in which
the data is stored. The system does search through all records sequentially. It
bases its search on a number of conditions defined in the SELECT statement.
The SELECT statement does not modify the data in the database. It is used
simply to query the data. Whereas only one user at a time can modify data, any
number of users can query or select the data concurrently.
The SELECT statement works at the table level; the output is also a table
consisting of 0, 1, or more records. If the query is very specific, the output may
consist of only one record. The structure of a SELECT statement is directly
derived from the table structure. It takes the following general form:
SELECT columns ...
FROM table(s) ...
WHERE each row fulfills the condition(s) ...
Programming features
5-9
Database handling
The following sections provide information on SQL syntax and using SQL.
SQL syntax
The general structure of an SQL query is as follows:
SELECT <select list>
[ FROM <from list> ]
[ WHERE <where condition> ]
[ GROUP BY <group list>
[ HAVING <having condition> ] ]
[ ORDER BY <order by list> [WITH RETRY [REPEAT LAST ROW] ]]
[ SET SPECIFICATION ]
For full details of any of the above clauses of the SELECT statement, see the
sections below.
Programming features
5-10
Database handling
Include the keyword FOR UPDATE after a table name to indicate that the table
must be read with delayed lock. If you include FOR UPDATE after the keyword
SELECT in the SELECT clause, this indicates that all tables must be read with
delayed lock.
Operands
Operands 1 and 2 can consist of any of the following:
n numeric constant (for example, 10, 3.1415927)
n string constant (for example, "John", "mod")
n combined constant (for example, { 10 , "xyz" })
n table field, optionally followed by array indication
n pseudo field – for example, for indexes (<table>._index1, see “Combined
fields” earlier in this chapter)
n 4GL variable or pseudo variable (see “Using program variables” later in this
chapter)
n numeric expression (in which the operators +, -, *, /, \ are possible)
n string expression (in which the operator & and a substring are possible)
n special field – enum constants, date constants (using the function
date.to.num(Y,M,D) and date.num())
Programming features
5-11
Database handling
Operators
The following operators are possible:
n comparison operators
=, <, <=, >, >=, <>, !=
#>, #>=, #<, #<= (for combined fields)
n IN operator
Here, operand2 contains a set of values (or subquery). The system tests if the
value of operand1 is present in operand2. This operator replaces a number of
expressions separated by the OR operator. For example, both of the following
statements define the same condition:
WHERE ttadv200.cpac = "tc" OR ttadv200.cpac = "tt"
WHERE ttadv200.cpac IN ( "tc", "tt" )
n LIKE operator
The LIKE operator compares operand1 with operand2. Operand2 can contain
wild cards. For example:
WHERE name LIKE "[Tt]riton.*"
In this example, "Triton2.1" and "triton" are legal values. In this case,
operand2 is a regular expression. See the expr.compile() function for a list of
the possible features that the expression can contain.
n BETWEEN / INRANGE operator
These operators check whether operand1 falls within a specified range of
values. Operand2 and operand3 specify the lower and upper values of the
range. For example, both of the following statements define the same
condition – that is, they define a range from "tc" through "ts":
WHERE ttadv200.cpac >= "tc" AND ttadv200.cpac <= "ts"
WHERE ttadv200.cpac INRANGE "tc" AND "ts"
The operators BETWEEN and INRANGE are identical, except when you use
combined fields (see “SQL and combined fields” later in this chapter).
Programming features
5-12
Database handling
n EXISTS operator
This operator tests whether certain records do or do not occur. It is used in
conjunction with subqueries. The following example selects only those items
on the order list with an order quantity greater than 100:
select tiitm001.item, tiitm001.dsca
from tiitm001
where exists
( select timps052.*
from timps052
where timps052.item = tiitm001.item and
timps052.qana > 100 )
n REFERS TO operator
See “References” later in this chapter.
Programming features
5-13
Database handling
This clause determines the order of the records in the output table. In the <order
by condition>, you list one or more fields from the <select list> in the SELECT
clause. The field listed first in the ORDER BY clause takes precedence. You can
list the fields by name or you can specify an index to their position in the
SELECT clause. For each field in the <order by condition>, you can indicate if
the order is to be ascending (default) or descending – for example, ORDER BY 1
asc, 2 desc.
If retry points are included, you must use ORDER BY to ensure that the
sequence after return to the retry point is identical to the one used the first time.
After a jump to a retry point, it is important that the query continues at its
position in the selected set at the time that the retry occurred. By using the WITH
RETRY addition this is easy to realize. By performing a commit.transaction(),
the values for the retry conditions are saved. In case of a jump to a retry point,
the query continues, starting from the values saved during the
commit.transaction(). In the case of WITH RETRY the new set starts after the
saved values. In the case of WITH RETRY REPEAT LAST ROW, the set starts
at the saved value; so the last record is read again. In the case of WITH RETRY
REPEAT LAST ROW, enter a commit.transaction() in the SELECTEOS part
of the select statement to prevent a new build-up of the query in some cases.
Programming features
5-14
Database handling
Set specification
Baan SQL supports the following options in relation to sets:
n Maximum set size.
With this option you can indicate the maximum number of records the query
can produce. The syntax is:
SELECT .... [from][where] AS SET WITH <number> ROWS
n Prepared set.
With this option, the entire set is retrieved before the first record is returned.
The set is temporarily stored. This option is useful when a process
simultaneously selects and maintains (or deletes or adds) records. In this case,
changes must not be visible in the selected records. The prepared set option
forces a consistent read. The syntax is as follows:
SELECT ... [from][where] AS PREPARED SET
n Maximum set size and prepared set.
You can combine both options as follows:
SELECT ... [from][where] AS PREPARED SET WITH <number>
ROWS
Programming features
5-15
Database handling
SELECT clause
In the <select list> of the SELECT clause, program variables are used to indicate
the elements in which the query results must be stored. You can do this by
explicitly specifying a program variable. The general syntax is:
<select part>:<program variable>
For example:
SELECT ppmod123.field1:my_val1
Or you can directly use a program variable (a table or field name) from the
calling program in the <select list>. For example:
SELECT ppmod123.field1
In the first example, the program places the result in the <program variable>. In
the second example, the name in the query and the name of the program variable
are identical.
FROM clause
You can also use program variables in the WHERE clause. When evaluating the
query, the program loads the values of the program variables into the query and
includes them in the evaluation. This link can be realized by incorporating a
program variable in the query, preceded by a colon [:]. For example:
WHERE ppmod123.field1 = :myval1
Note
A table field can be a program variable as well as a query variable. Note that the
following query:
select tccom010.*
where tccom010.cuno = tccom010.cuno
The latter selects one record; the former selects all records from the table
tccom010, as tccom010.cuno by definition equals tccom010.cuno for each row.
Programming features
5-16
Database handling
References
Retrieving references to a record
In the standard SQL interface, you can retrieve references to a record as follows:
| Suppose that tiitm001 has a reference to tccom010
| (field ’cuno’), and to tccom011 (field ’suno’)
table ttiitm001
table ttccom010
table ttccom011
SELECT tiitm001.*, tccom010.*, tccom011.*
FROM tiitm001, tccom010, tccom011
WHERE tiitm001.cuno = tccom010.cuno AND
tiitm001.suno = tccom011.suno
Programming features
5-17
Database handling
REFERS TO syntax
A REFERS TO statement has the following form:
<from> REFERS TO <to> [PATH <path> [,<path>...]]
[UNREF<mode>]
Programming features
5-18
Database handling
Example
SELECT ttadv100.*
FROM ttadv100, ttadv101
WHERE ttadv101.cmod BETWEEN "aaa" and "azz"
AND ttadv101 REFERS TO ttadv100 UNREF <UNREF_mode>
AND ttadv100.cpac BETWEEN " " and "zz"
Programming features
5-19
Database handling
In the following example, the REFERS TO clause is used to achieve the same
result. If the program does not find the reference, it fills the field with reference
characters.
Table ttccom010
Table ttccom011
Programming features
5-20
Database handling
Example
SELECT tccom010.*
FROM tccom010, tiitm001
WHERE tiitm001.cuno = :tiitm001.cuno AND
tiitm001.cuno REFERS TO tccom010
Company numbers
The company number used during execution of a BAAN 4GL query is the
current company number. The current company number is:
n The default company number (defined in the session "Maintain User Data" )
n A company number specified by the compnr.check() function
Example
The record where the field ttadv100._compnr = 000 belongs
to the (physical) table ttadv100000
The record where the field ttadv100._compnr = 200 belongs
to the (physical) table ttadv100200
Programming features
5-21
Database handling
This query lists all records from table ttadv100200 where ttadv100.cpac has the
value ’tt’.
You can use <table>._compnr in the following ways:
n <table>._compnr = <number> or <number> = <table>._compnr where
<number> specifies an integer number. The value of <number> is taken as
the company number. It must be a 3-digit number.
n <table>._compnr = <string> where <string> specifies a list of company
numbers, separated by commas [,]. This construction can be used to check a
condition for a range of company numbers. The string can contain only digits
and commas. (So, you specify company numbers 0 and 23 by
<table>._compnr = "000,023"). For example:
SELECT ttadv100.*
WHERE ttadv100._compnr = "200,300" AND <condition>
This query results in a list of the records from the table ttadv100 (with
company numbers 200 and 300) that match <condition>.
n <table>._compnr IN <set specification> where <set specification> is a set of
constants or a subquery.
Sets must not contain duplicate values. See IN operator in “WHERE
<where condition>” section earlier in this chapter.
Programming features
5-22
Database handling
Programming features
5-23
Database handling
If a child field of a combined field is not specified, the value of this field is free
and is not included in the condition. For example:
WHERE ppmod001.comb1 #>= {"adv", "000", "100"} AND
ppmod001.comb1 #<= {"zzz", "999"}
As the field ppmod001.compno has no upper limit, all values greater than or
equal to 100 are fetched.
Programming features
5-24
Database handling
As with other combined fields, children of index fields for which no value is
specified are not included in the condition. However, you can leave fields
unspecified only at the end of the index, not in the middle.
An index’s pseudo field cannot be used in the query preceded by ’:’.
Here, {"adv", "050" "123"} meet the conditions, but the combination {"uvw",
"123", "300"} does not, because of the last child field.
For this construction we define the INRANGE statement. With INRANGE,
the preceding example becomes:
WHERE ppmod001.comb1
INRANGE {"adv", "000", "100"} AND
{"zzz", "999", "200"}
With INRANGE, the boundaries indicated apply to each separate field (usual
in print sessions).
n Secondly, it can mean that all records are selected for which the combined
field (regarded as one single field) lies between the boundaries indicated. For
example:
WHERE ( ppmod001.comb1 >= {"adv", "000", "100"} AND
ppmod001.comb1 <= {"zzz", "999", "200"} )
With BETWEEN, the fields in the combined are regarded as one field; the
boundaries apply to the combined field as a whole.
Programming features
5-25
Database handling
If the field consists of one single element, INRANGE and BETWEEN are
equivalent.
SQL subqueries
Baan SQL permits the use of subqueries. These are SELECT statements in the
WHERE clause of another SELECT statement.
Defining nested queries can be very difficult. It is best to define the subquery of
the lowest level first and the main question last.
Example 1
Select those prices from the item file that are above average. When calculating
the average, the system should not take prices less than or equal to zero into
account.
SELECT tiitm001.copr | cost price
FROM tiitm001
WHERE tiitm001.copr >
( SELECT avg(tiitm001.copr)
WHERE tiitm001.copr > 0 )
ORDER BY tiitm001.copr
In this case, the subquery should only produce one result (here the average cost
price). If the subquery produces more than one result, use the operators IN and
EXISTS.
Example 2
Select the numbers and names of all suppliers who have yet to deliver.
SELECT tccom020.suno, tccom020.nama
FROM tccom020 | Suppliers
WHERE EXISTS
( SELECT *
FROM timps053 | Purchase orders
WHERE timps053.suno = tccom020.suno )
SELECT tccom020.suno, tccom020.nama
FROM tccom020
WHERE tccom020.suno IN
( SELECT timps053.suno
FROM timps053
GROUP BY timps053.suno )
Programming features
5-26
Database handling
SQL programming
There are two ways to use Baan SQL in a Baan 4GL program. You can embed it
in the language (embedded SQL), or you can use Baan 4GL functions (dynamic
SQL).
Embedded SQL
Syntax
The following loop structure enables the use of SQL as part of the language:
SELECT < set definition (= actual query, see "SQL Syntax"
earlier in this chapter) >
[ SELECTBIND ( number, var) ] ...
[ WHEREBIND (number, expression) ] ...
[ SELECTDO
< operation(s) on all selected records > ]
[ SELECTEOS
< operation(s) after last selected record > ]
[ SELECTEMPTY
< operation(s) if nothing has been selected > ]
[ SELECTERROR
< operation(s) in case of an error condition > ]
ENDSELECT
Description
Data is selected on the basis of the condition specified in the SELECT statement.
The operations between SELECTDO and ENDSELECT are performed on each
record from the selected set. The loop ends either when the program has handled
the entire set or the program encounters a BREAK command.
In the case of an error, the program executes the SELECTERROR part. A
CONTINUE statement in the SELECTERROR part causes the next record to be
processed. If there is no SELECTERROR section, the program generates a
BREAK as the default action. Note that errors are returned only if the shell
variable ERROR.BYPASS = 1.
The SELECTEOS part is executed after the SELECTDO of the last selected
record. The intention of the SELECTEOS part is that before the program
encounters a ’break’ from the loop you can give a commit.transaction(), while a
commit.transaction() may cause a retry. If a commit.transaction(), given after
the ENDSELECT part, causes a retry, then the whole query must be regenerated.
Programming features
5-27
Database handling
If the SELECTDO part is suppressed, the program encounters a ’break’ from the
loop after the first selected record. If the SELECTDO part is suppressed but the
SELECTEOS part occurs, the program will select the whole set of records.
In order to bind pseudo variables, the functions SELECTBIND and
WHEREBIND have been added. Pseudo variables have the form ’:<number>’. A
special bind function is then used to link a program variable to the pseudo
variable. For example:
SELECT ppmod123.field1:5, ppmod123.field2:6
SELECTBIND(5, my_val1)
SELECTBIND(6, my_val2)
SELECTDO
....
ENDSELECT
Example
table tppmod090
long total, m_val
m_val = 25
SELECT ppmod090.fld1, count(*):1
FROM ppmod090, ppmod091 | this line is optional
WHERE ppmod090.fld2 = ppmod091.fld5 AND
ppmod091.fld3 > :m_val
GROUP BY ppmod090.fld1
ORDER BY 2
SELECTBIND(1,total)
SELECTDO
print_info(ppmod090.fld1, total)
SELECTERROR
message("Error %d occurred", db.error)
break
ENDSELECT
Programming features
5-28
Database handling
See “Dynamic SQL” below for an example of the same query executed using
dynamic SQL.
Dynamic SQL
Dynamic SQL enables a program to form an SQL statement during execution, so
that the contents of the statement can be determined, for example, by user input.
Functions
To use Dynamic SQL, the following functions are available:
Functions Description
sql.parse() Query definition.
sql.set.rds.full() This sets the size of the RDBMS buffer.
sql.select.bind() These functions link program variables to the
sql.where.bind() query's pseudo variable. In Dynamic SQL, all
non-external program variables used in the
query must be linked to a pseudo variable with
these functions.
sql.exec() This function initializes the query. It gives the
variables their proper values.
sql.fetch() This function executes the query. It reads one
result on which operations can be performed.
This function must be invoked for each separate
record from the selected set.
sql.break() Stops execution of the query. Any interim
results are cleared.
sql.close() Deletes (all) internal information belonging to
this query.
Programming features
5-29
Database handling
Sequence of actions
By using these functions a query, once defined, can be reused optimally. The
sequence of the actions is then:
sql.parse, sql.bind, sql.exec, sql.fetch, sql.fetch, ...,
sql.break
sql.bind, sql.exec, sql.fetch, sql.fetch, ...,
sql.break
sql.close
In this way you can prevent expensive sql.parse() calls, while still working with
new arguments.
This flow is automatically generated from an embedded SQL program by bic6.2.
Usually, the programmer will therefore opt for embedded SQL, the more so,
since it automatically binds 4GL variables.
Example
Table tppmod090
Long sql
Long total, m_val
m_val = 25
if ( not sql ) then
sql = sql.parse(
"select ppmod090.fld1, count(*):1 " &
"from ppmod090, ppmod091 " &
"where ppmod090.fld2 = ppmod091.fld5 AND " &
"ppmod091.fld3 > :2 " &
"group by ppmod090.fld1 " &
"order by 2")
endif
sql.select.bind(sql, 1, total)
sql.where.bind(sql, 2, m_val)
sql.exec(sql)
while ( true )
on case ( sql.fetch(sql) )
case eendfile:
break
case 0:
print_info(ppmod090.fld1, total)
continue
default: | error
message("Error %d occurred", db.error)
endcase
break
endwhile
sql.break(sql)
Programming features
5-30
Database handling
See “Embedded SQL” earlier in this chapter for an example of the same query
executed using embedded SQL.
The DB.RETRY flag indicates that we are dealing here with updates with
SELECT FOR UPDATE and retry points. This flag ensures that the actual
update action is postponed until the commit. The db.update() and db.delete()
functions with the DB.RETRY flag can be invoked only in combination with
SELECT FOR UPDATE. The use of db.insert() with the DB.RETRY flag, on
the other hand, is not linked to the use of SELECT FOR UPDATE.
Programming features
5-31
Database handling
Client tracing
When TT_SQL_TRACE is set, the output from the client process is written to
stderr. To keep this information, you must call the bshell with the options "-
keeplog" and "-logfile <log file name>". For example:
bx6.1 -- -keeplog -logfile mylogfile -set
TT_SQL_TRACE=02000
This enables TT_SQL_TRACE with value 02000. The output is written to the
file "mylogfile" in the current working directory.
Server tracing
When TT_SQL_TRACE is set, the output is written to a file named "dbs.log".
This file is located in the current working directory when the Database Server
runs locally (on same host as Display Server). When the database is remote, it is
written in the login directory of the corresponding user on that remote system. To
enable logging of TT_SQL_TRACE in the file "dbs.log", you must also set the
environment variable DBSLOG, as follows:
DBSLOG=02000
The "02000" is an octal value, and can be OR-ed with other variables. The
meaning of the other values is described in a separate document (Logging
Database Information (DBSLOG)).
Programming features
5-32
Database handling
Query identification
A QueryIdentifier (QID) identifies each query. This makes it easy to find out
which output in the Client log file is related to the output of the Server log file.
Trace options
The following values for TT_SQL_TRACE are available (C indicates that an
option can be used for the client; S indicates that it can be used for the server):
1. TT_SQL_TRACE=040 (C) Show queries with their QID
2. TT_SQL_TRACE=02000 (C) Show calls of internal SQL
functions
3. TT_SQL_TRACE=0200 (C) Show query execution times
4. TT_SQL_TRACE=04000 (C+S) Show query evaluation plan
5. TT_SQL_TRACE=020000 (S) Show FullTableScan
6. TT_SQL_TRACE=010000 (S) Show Query Evaluation Plan
In sql.dbg, this produces the results of both options 010000 and 0200.
TT_SQL_TRACE=040
Shows all queries (query text) which are evaluated. For example:
Evaluated Query (QID : 4)
select ttadv450.vers, ttadv450.rele, ttadv450.cust,
ttadv450.expi, ttadv450.mess
where ttadv450._index1 = {:clan, :1, :2}
TT_SQL_TRACE=02000
Shows calls of internal SQL functions, including their arguments. For example:
[SqlParse: before parse] SqlId : 200db008 - QID : 4 - Status : 0
Trans 1 Mode 0 Query:
select ttadv450.vers, ttadv450.rele, ttadv450.cust, ttadv450.expi,
ttadv450.mess
where ttadv450._index1 = {:clan, :1, :2}
[SqlParse: after parse (e = 0)]
SqlId : 200db008 - QID : 4 - Status : 2
[SqlWhereBind for clan] SqlId : 200db008 - QID : 4 - Status : 2
Value(str): ’2’
[SqlWhereBind for 1] SqlId : 200db008 - QID : 4 - Status : 2
Value(str): ’tt’
[SqlWhereBind for 2] SqlId : 200db008 - QID : 4 - Status : 2
Value(str): ’gfdmnucal ’
Programming features
5-33
Database handling
WARNING: The line following the message "SqlFetch returns .." shows the result of the
fetch. The order of the fields is not always the order as mentioned in the
SELECT clause.
TT_SQL_TRACE=0200
Shows query execution times. For example:
================================================
Fetch times of Query (QID : 12) in SqlBreak :
select ttdsk360.*
where
(ttdsk360.user = :logname$ or ttdsk360.user = :1)
order by ttdsk360.user desc, ttdsk360.cpac desc,
ttdsk360.rsst desc, ttdsk360.rsid desc
------------------------------------------------
Nr Rows Fetched : 39
Fetch Time for 1st Row : 0.060 sec
Max Fetch Time : 0.060 sec
Average Fetch Time : 0.000 sec
Average Fetch Time (except Max) : 0.000 sec
================================================
A value 0.000 means that the time to fetch was too small to be measured. This
can happen when the result is already available in the client. In that case, fetching
is (globally seen) only copying from one memory location to another.
TT_SQL_TRACE=04000
Show the query evaluation tree. There is different output for client and server.
The client shows how the query is distributed over different databases (normally
there is one database). The server shows how the query is evaluated. This can be
different for different databases. The example shows the evaluation in a non-SQL
database driver. In the examples, the same query is used as in the example of
TT_SQL_TRACE=040.
Client Side:
Expression Tree (QID : 4):
[11] flag 011 cost 0 next_eval 12 next 12
cost 0 0 nr 0
Operand1:
Database View Id 0 - Drivers:
Programming features
5-34
Database handling
Server:
Generated Query Execution Tree:
Sql id 6 company 000 sid 1 flag 1 (QID : 4)
Output Columns (total 5)
[ 0] vers idx 0 type 6 size 4 depth 1
Programming features
5-35
Database handling
Programming features
5-36
Database handling
Field cust:
AND (011)
[16] flag 011 cost 0 next_eval -1 next -1
cost 0 0 nr 0
Operand1:
Operator: QpsPermOper
Operand2: ’-1’
AND (011)
[17] flag 011 cost 0 next_eval -1 next -1
[1] End of Query
There are a lot of numbers/state values in this tree. Most of them are for internal
use only.
TT_SQL_TRACE=020000
Shows all tables for which FullTableScan is performed. This can depend on
which database is used. For example:
FullTableScan for table ttdsk355 (QID : 2)
The QID refers to the query. This can be found in the client trace file.
TT_SQL_TRACE=010000
Shows Query Evaluation Plan (QEP). This also depends on which database is
used. For example:
Query Evaluation Plan (QID : 30)
------------------------------------------------
Table tccom000 (alias: a): IndexSearch with condition(s):
SrchOper for tccom000 compnr 000 index 1 (mode 0)
Field ncmp:
Equal: [=] Bind (Col ncmp) Value: ’812’
Forced Order: Ascending (index 1)
Table tcmcs046 (alias: b): IndexSearch with condition(s):
SrchOper for tcmcs046 compnr 000 index 1 (mode 6)
Field clan:
Equal: [REF (clear)] Index Col key 1 mode 5 equal 0
tccom000(a).clan
Table tcmcs002 (alias: c): IndexSearch with condition(s):
SrchOper for tcmcs002 compnr 000 index 1 (mode 6)
Field ccur:
Equal: [REF (clear)] Index Col key 1 mode 5 equal 0
tccom000(a).ccur
================================================
Programming features
5-37
Database handling
The query which belongs to this QEP is shown in the client log file
(TT_SQL_TRACE=040) as follows:
Evaluated Query (QID : 30)
Select tccom000.*, tcmcs002.*, tcmcs046.*
From tccom000, tcmcs002, tcmcs046
Where tccom000.ncmp = :company.nr
And tccom000.ccur refers to tcmcs002 unref clear
And tccom000.clan refers to tcmcs046 unref clear
order by tccom000.ncmp
Programming features
5-38
Database handling
Error handling
There are two broad categories of errors. Errors generated by the operating
system (numbers 1 - 99) and errors generated by the database system (numbers
100 - 900). See Chapter 10, Errors.
To keep the messages to be sent over the network to a minimum, database
actions and messages must be buffered as much as possible. Buffering updates
means that as few updates as possible return error codes. These, after all, cause a
rollback and a return to a retry point. It is therefore possible to allocate flags to
updates indicating the action to be taken by the system when a database action
fails. The database server will then no longer execute a rollback, but a follow-up
action.
Programming features
5-39
Database handling
The eflag
For a number of errors it is possible to indicate which action the system must
carry out when the error occurs. You can add these to a database action with the
<eflag>. For example:
db.insert(table, DB.RETRY [, eflag])
db.update(table, DB.RETRY [, eflag])
db.delete(table, DB.RETRY [, eflag])
Programming features
5-40
Database handling
Example
table ttiitm001
db.retry.point()
SELECT tiitm001.*
FROM tiitm001 FOR UPDATE
WHERE tiitm001.item between :item.f and :item.t
SELECTDO
......
db.insert(ttiitm001, DB.RETRY, db.skip.dupl)
ENDSELECT
In this case, the flag ’db.skip.dupl’ causes the system neither to go back to the
retry point nor return an error code when adding an already existing record.
Programming features
5-41
Database handling
5 It is not necessary to bind external variables and database fields used in the
query as substitution variables. In embedded SQL local variables are bound
automatically.
6 The program executes the query the first time the function sql.fetch() is
called. If reading in the entire set is unnecessary (so no order by, group by,
and so on), the program only physically retrieves records at each sql.fetch().
This avoids an entire set being retrieved when only part of it is used. When
the set is no longer necessary call sql.break() to clear the remaining records.
7 Use ORDER BY to ensure that the records are retrieved in the correct
sequence. If an index can be used for the ORDER BY, no sort action will
take place beforehand.
8 The program will execute a Full Table Scan (FTS) if the operators NOT
INRANGE, IN, LIKE are used or if no index (or part of an index) is used.
This means that the system checks beforehand whether all records in the table
meet the conditions of the query. This precludes optimization. If only the first
part of an index (combined or normal field) is used, the system uses that
index to search the table.
When GROUP BY is used, the system first determines the entire set
(prepared set), before producing the first record. The same thing happens if
the operator is preceded by an expression –for example, WHERE
<table.field1> & <table.field2> = "...........". Note that the various
subexpressions separated by AND or OR cannot be combined for
optimization.
9 It is possible to have the program carry out commits at certain points in the
select loop. If retry points are included, use of ORDER BY is required to
ensure that the sequence after return to the retry point is identical to the one
used the first time. See also the practical examples.
10 If a transaction adds or processes records, it depends on the database if the
same transaction can also process new records without a select being carried
out again. To ensure that new records are processed in any case, a commit
and a new select are required. To ensure that new records are not processed,
define the set at the point of the select (prepared set).
11 When using transactions, the first priority should be that the actions within
the transaction constitute a logical unit. For reasons of performance, update,
insert, and delete actions can be combined up to a number of 256 (this is an
average, not a limit) per transaction. For example, programs processing
orders should execute one commit.transaction() for each order.
Programming features
5-42
Database handling
12 It may be necessary to know how far the program had advanced before it
moved back to the retry point. If the key consists of more than one field, it is
probably possible to have the program execute a commit.transaction() when
a particular key field changes. If a key consists of order number and order
line, for instance, a commit by order number would be preferable to a commit
by order line. Care should be taken in programs that print and process data in
one run. An abort transaction restores the database but not the output to the
printer. In such cases a commit must be executed for each print line to
prevent lines being printed twice.
For example:
save.orno = start
select for update order line.orno order line.pono
from order line
where order line.orno >= :save.orno
selectdo
if ( save.orno <> order line.orno ) then
commit.transaction()
save.orno = order line.orno
endif
update actions()
endselect
commit.transaction()
Programming features
5-43
Database handling
In this case REPEAT LAST ROW is not used, because when retry is done, the
value which was present at the stage of commit.transaction() has certainly been
saved.
Programming features
5-44
Database handling
Notice that this works only when the db.update() and commit.transaction() are
done before the print and the collect statement. An alternative to this solution is
described in situation 5.
Programming features
5-45
Database handling
lsp stands for last processed. pdno and pono are together the index of cst001. The
’lsp.’ variables should always be used for this kind of saving within selects. These
variables save which record has already been printed/collected. The
total.order.quan can always be added because setting to zero is done for each
retry again.
Programming features
5-46
6 Data Access Layer (DAL)
Overview
In BAAN applications, the standard program (STP) provides much of the default
functionality for a session. In previous versions of the software, changes or
additions to the default functionality for a session were programmed in a single
script that was associated with the session. Both user interface actions and
database actions were programmed in this script.
In BaanERP, user interface actions and database actions have been separated.
The Data Access Layer (DAL) now handles database interaction. Programmers
create a user interface (UI) script to change the default behavior of a session.
They create a DAL script to program all the logical integrity rules for a particular
table. So the DAL ensures the logical integrity of the database. As in previous
versions of the software, the database server ensures the referential integrity of
the database.
The DAL script for a particular table has the same name as that table. It is
implemented as a DLL that can be accessed by user interface scripts (via the
standard program), by other DALs, and by external programs (via the Common
Data Access Server (CDAS). The following diagram illustrates the overall
relationship of these components.
Programming features
6-1
Data Access Layer (DAL)
Business methods
In addition to performing data integrity checks, the DAL provides business
methods for handling non-interactive database modifications such as printing
sales orders or posting all orders to history.
A business method is a function that performs a task that involves manipulating
and/or checking one or more tables in the database. The function is programmed
in a DAL script and can be called directly from a UI script. It must be
programmed in the DAL script of the most relevant table.
Users can activate a business method with a single command. There is then no
further user interaction. The UI script calls the relevant function in the DAL
script. The function performs all operations to complete the required task. The
user must wait until the business method finishes before continuing with other
tasks. However, if a progress window is provided, the user can cancel the
business method by clicking on the Cancel button.
The UI script starts a business method by calling the
dal.start.business.method() function.
Programming features
6-2
Data Access Layer (DAL)
DAL terminology
Class A description of a group of objects with similar properties,
common behavior, common relationships, and common
semantics. A DAL class corresponds to a BAAN table
definition.
Object An instance of a class. It consists of data and the methods
(code) to manipulate the data. The data of a DAL object
corresponds to a record in a BAAN table.
Object set All objects of a class, as stored in the database. A DAL
object set corresponds to a BAAN table.
Property An attribute of an object. A DAL property corresponds to a
field in a record in a BAAN table.
Method The implementation of an operation for a particular class. It
provides a means of retrieving and manipulating data
(properties) in objects. Method is another name for an
operation or function.
Hook A logic integrity rule. Hooks are implemented in the DAL as
functions.
Programming features
6-3
Data Access Layer (DAL)
Example
If a user changes the address of a customer on a form, the standard program
changes the address for that customer in the database via the DAL. If you want
certain restrictions to apply to the update action, you can program a property
hook in the DAL of the session’s main table to impose these restrictions. For
example:
when the address changes:
if changed into something valid then
accept
else
reject
endif
UI function calls
The UI script can use either the db.* functions or the DAL Data Access Methods
(DAM) to manipulate the database. The db.* functions are direct database calls.
They do not use the DAL. In this case, any logic integrity checks required must
be programmed in the UI script itself. This means that they cannot be reused by
other sessions. In preference, use the DAL Data Access Methods. These access
the database via the DAL, so all necessary checks are automatically performed.
Function flow
When the DAL is used to manipulate the database, the main steps involved are as
follows:
1 The user issues a command through the user interface to access a record in
the database.
2 The standard program loads the appropriate DAL and calls the hooks in the
DAL to check the integrity rules for the object.
3 If the particular database action is permitted, the standard program issues the
appropriate database call.
4 After the database has been updated, the DAL can perform further checks to
determine whether or not data is passed back to the user interface.
5 The standard program passes data back to the user interface (provided that the
integrity rules permit this).
Programming features
6-4
Data Access Layer (DAL)
One-way interaction
Note that because the DAL can be used in situations where there is no user
interface, the DAL cannot call functions in the UI.
DAL hooks
A hook is a function, with a predefined name, that the DAL programmer
programs in a DAL script. The function is used to program logic integrity rules
for database access. The DAL script is compiled into a DLL.
When a user issues a command to access the database, the standard program
loads the DAL DLL for the object being accessed and calls the hooks to perform
the integrity checks. Provided that a DAL script exists for an object set being
accessed, the standard program always ensures that the hooks in the DAL are
called at the appropriate times.
A DAL script can contain two types of hooks:
n Property hooks
n Object hooks
Programming features
6-5
Data Access Layer (DAL)
Property hooks
Property hooks are hooks that relate to a specific property (that is, a table field).
Property hooks replace the check.input event sections for fields of the main
table. If there is a DAL for an object set, the property hooks are called to perform
the necessary field checks. Any check.input sections in the UI script are ignored.
So, if a UI script contains check.input sections for fields of the main table, you
must replace these by property hooks in the DAL. In the UI script, check.input
sections are retained for non-database form fields. Such sections are executed
even if a DAL exists.
Currently there is only one property hook: fieldname.check(). The standard
program calls this hook when inserting or updating an object.
fieldname.check()
Syntax
function extern long ppmmmvss.bbbb.check( long has_changed
[, long element] )
Description
Use this hook to program logical integrity rules for a specified field. The function
name is ppmmmvss.bbbb.check(), where pp is the package code, mmm is the
module code, vss is the table number, and bbbb is the field name.
Arguments
has_changed This indicates whether the value of the field has changed. It is
set by the standard program and can be tested in the hook.
Possible values are:
0 not changed
DAL_NEW change caused by inserting a new object
DAL_UPDATE change caused by updating an existing object
element This is set for array fields only. It indicates the index of the
array element that must be checked.
Return values
This hook returns 0 if the value of the field is accepted. It returns a negative
value (DALHOOKERROR) if the value is not accepted.
Programming features
6-6
Data Access Layer (DAL)
See also
“Property methods” later in this chapter
Example
A property hook programmed in DLL tdsls040:
function extern long tdsls040.oqua.check(long has_changed)
{
if tdsls040.stat = tdsls.stat.invoiced and
has_changed then
dal.set.error.message("tdsls44041")
| Order is already invoiced, cannot change
| quantity
return(DALHOOKERROR)
endif
...
return(0)
}
Object hooks
Object hooks are used for checking the logic integrity of objects (that is, records
in a table).
Object hooks replace the before.read, after.read, before.write, after.write,
before.rewrite, after.rewrite, before.delete, and after.delete subsections in the
main.table.io section of the UI script.
If there is a DAL for an object set, the standard program calls the object hooks in
the DAL every time that a DAM is executed for that object set. The object hooks
perform the necessary checks to ensure the logical integrity of the objects being
accessed. Any of the above mentioned sections in the UI script are ignored. So, if
a UI script contains any of these sections, you must replace these by object hooks
in the DAL.
Programming features
6-7
Data Access Layer (DAL)
before.destroy.object()
after.destroy.object
Save object hooks
before.save.object()
after.save.object()
After commit transaction hook
after.commit.transaction()
Method is allowed hook
method.is.allowed()
Programming features
6-8
Data Access Layer (DAL)
before.open.object.set()
Syntax
function extern long before.open.object.set()
Description
Use this to program checks that determine whether opening of the object set is
permitted.
If this hook exists, it is executed after the before.program event section for the
main table. It is also called for every first access to a DAL by business methods
or Data Access Methods.
You can also use this section to program query extensions.
Return values
The hook returns 0 if opening of the object set is permitted. If the hook returns a
negative value (DALHOOKERROR), the session is aborted (if the hook is called
by the STP) or the method returns an error (if the hook is called by a DAM or a
business method).
before.get.object()
Syntax
function extern long before.get.object( long dir )
Description
Use this to program checks that determine whether reading a record is permitted.
The dir argument is set by the STP or CDAS and specifies the object being read.
The possible values are:
DAL_GET_FIRST DAL_GET_NEXT DAL_GET_PREV
DAL_GET_LAST DAL_GET_FIND DAL_GET_CURR
This object hook replaces the before.read subsection of the main.table.io event
section in a UI script. If there is a DAL for an object set, this hook is called to
perform the necessary checks. Any before.read sections in the UI script are
ignored. So, if a UI script contains before.read sections for the main table, you
must replace these by before.get.object() hooks in the DAL.
Programming features
6-9
Data Access Layer (DAL)
Return value
The hook returns 0 if reading of the record is permitted. Negative return values
(DALHOOKERROR) are ignored by the calling program.
Example
function extern long before.get.object( long dir )
{
return(0)
}
after.get.object()
Syntax
function extern long after.get.object( long dir )
Description
Use this to program checks that determine whether reading a record is permitted.
The checks are performed after the record has been retrieved from the database.
The dir argument is set by the STP or CDAS and specifies the object being read.
The possible values are:
DAL_GET_FIRST DAL_GET_NEXT DAL_GET_PREV
DAL_GET_LAST DAL_GET_FIND DAL_GET_CURR
This object hook replaces the after.read subsection of the main.table.io event
section in a UI script. If there is a DAL for an object set, this hook is called to
perform the necessary checks. Any after.read sections in the UI script are
ignored. So, if a UI script contains after.read sections for the main table, you
must replace these by after.get.object() hooks in the DAL.
Notes
It is preferable to use a query extension in the before.program section of the UI
script instead of this hook. So, only use this hook if a query extension is not
possible.
The standard program ignores messages set in this hook.
Return value
The hook returns 0 if reading of the record is permitted. If the hook returns a
negative value (DALHOOKERROR), the object is skipped.
Programming features
6-10
Data Access Layer (DAL)
Example
| after.get.object hook
Programming features
6-11
Data Access Layer (DAL)
before.destroy.object()
Syntax
function extern long before.destroy.object()
Description
Use this to program checks that determine whether deleting a record is permitted.
This object hook replaces the before.delete subsection of the main.table.io
event section in a UI script. If there is a DAL for an object set, this hook is called
to perform the necessary checks. Any before.delete sections in the UI script are
ignored. So, if a UI script contains before.delete sections for the main table, you
must replace these by before.destroy.object() hooks in the DAL.
Return value
The hook returns 0 if deleting the record is permitted. If the hook returns a
negative value (DALHOOKERROR), the transaction is aborted.
Example
function extern long before.destroy.object()
{
if tdsls040.stat = tdsls.stat.invoiced then
dal.set.error.message("tdsls44041")
| You cannot delete an invoiced transaction
return(DALHOOKERROR)
endif
...
return(0)
}
after.destroy.object()
Syntax
function extern long after.destroy.object()
Description
Use this to update referenced tables after the current object has been deleted.
This object hook replaces the after.delete subsection of the main.table.io event
section in a UI script. If there is a DAL for an object set, this hook is called to
perform the necessary actions. Any after.delete sections in the UI script are
Programming features
6-12
Data Access Layer (DAL)
ignored. So, if a UI script contains after.delete sections for the main table, you
must replace these by after.destroy.object() hooks in the DAL.
Return value
The hook returns 0 if successful. Negative return values (DALHOOKERROR)
are ignored by the calling program.
Example
function extern long after.destroy.object
{
return(0)
}
before.save.object()
Syntax
function extern long before.save.object( mode )
Description
Use this to program checks that determine whether saving a record is permitted.
The mode argument is set by the standard program. The possible values are:
DAL_NEW indicates a new record
DAL_UPDATE indicates a record being updated
This object hook replaces the before.write and before.rewrite subsections of the
main.table.io event section in a UI script. If there is a DAL for an object set, this
hook is called to perform the necessary checks. Any before.write and
before.rewrite sections in the UI script are ignored. So, if a UI script contains
before.write and before.rewrite sections for the main table, you must replace
these by before.save.object() hooks in the DAL.
Return value
The hook returns 0 if saving the record is permitted. If the hook returns a
negative value (DALHOOKERROR), the transaction should be canceled.
If the hook was called directly by the standard program, the transaction is
canceled automatically. If the hook was not called by the standard program, the
transaction must be canceled by calling abort.transaction() or abort.io(),
typically in the UI script.
Programming features
6-13
Data Access Layer (DAL)
Example
function extern long before.save.object(long mode)
{
if mode = DAL_NEW then
| this is code from before.write subsection
else
| this is code from before.rewrite subsection
endif
return(0)
}
after.save.object()
Syntax
function extern long after.save.object( mode )
Description
Use this to update referenced tables after a record has been added or updated.
The mode argument is set by the standard program. The possible values are:
DAL_NEW indicates a new record
DAL_UPDATE indicates a record being updated
This object hook replaces the after.write and after.rewrite subsections of the
main.table.io event section in a UI script. If there is a DAL for an object set, this
hook is called to perform the necessary actions. Any after.write and
before.rewrite sections in the UI script are ignored. So, if a UI script contains
after.write and after.rewrite sections for the main table, you must replace these
by after.save.object() hooks in the DAL.
Return values
The hook returns 0 if successful. Negative return values (DALHOOKERROR)
are ignored by the calling program.
Example
function extern long after.save.object( long mode )
{
if mode = DAL_NEW then
| this is code from after.write subsection
else
| this is code from after.rewrite subsection
endif
}
Programming features
6-14
Data Access Layer (DAL)
after.commit.transaction()
Syntax
function extern void after.commit.transaction()
Description
Use this to update other database tables after an update of the current table has
been committed to the database.
This object hook replaces the after.update.db.commit event section in a UI
script. If there is a DAL for an object set, this hook is called to perform the
required actions. Any after.update.db.commit sections in the UI script are
ignored. So, if a UI script contains a after.update.db.commit section for the
main table, you must replace it by an after.commit.transaction() hooks in the
DAL.
This hook is called only by the STP and CDAS. It is not called by Data Access
Methods or commit.transaction().
method.is.allowed()
Syntax
function extern long method.is.allowed( long method )
Description
This is a special hook for handling centralized authorizations. Use it to perform
checks that determine whether certain Data Access Methods are permitted for an
object. The method argument specifies the method to check.
The hook can be called from the UI script, but it is also called from the standard
program to check if certain operations are allowed.
Return values
TRUE the method is permitted
FALSE the method is not permitted
Programming features
6-15
Data Access Layer (DAL)
Example
function extern long method.is.allowed( long meth )
{
on case meth
case DAL_NEW:
if .... then
dal.set.error.message("error message")
return(false)
endif
break
case DAL_UPDATE:
...
break
case DAL_DESTROY:
...
break
endcase
return(true)
}
Programming features
6-16
Data Access Layer (DAL)
Property methods
Setting properties
In order to notify the DAL about a change in the value of a property, you must
use the dal.set.property() function to change the value. Using this function
ensures that the relevant property hooks are executed when the value is changed.
If you use an assignment or the db.* functions to change a property value, the
DAL is not notified of the change. Consequently, the property checks in the DAL
are not executed.
You can call this function from both UI and DAL scripts.
Retrieving properties
You can retrieve the value of the has_changed flag (see “Property hooks” earlier
in this chapter) for any property by calling dal.get.property.flag(). The property
must have been changed by the dal.set.property() function.
You can call this function from both UI and DAL scripts.
Query extensions
Query extensions define conditions that the standard program adds to the
SELECT, FROM, and/or WHERE clauses of a database query in order to
minimize the number of fields read from the main table and in order to retrieve
all reference table fields required by the UI and/or DAL scripts.
BaanERP provides the following functions for constructing query extensions:
n query.extend.select()
n query.extend.select.in.zoom()
n query.extend.from()
n query.extend.from.in.zoom()
n query.extend.where()
n query.extend.where.in.zoom()
You can program query extensions in the UI script and/or the DAL script. In the
UI script, you program the extensions in the before.program or before.zoom
sections. In the DAL script, you program the extensions in the
before.open.object.set() hook.
For a full discussion of query extensions, see “SQL Query extensions” in
U7167A US BaanERP Tools: Functions reference.
Programming features
6-17
Data Access Layer (DAL)
nr.of.errors = dal.count.error.messages()
if db.retry.hit() then
| Remove the error messages since last commit
dal.reset.error.messages( nr.of.errors )
endif
…
…
commit.transaction()
nr.of.errors = dal.count.error.messages()
…
commit.transaction()
while dal.get.error.message( message ) >= 0
report.message( message )
Programming features
6-18
Data Access Layer (DAL)
4GL functions
This table lists those 4GL UI functions that have DAL equivalents. If a DAL
exists for a particular table, it is preferable to use the DAL functions instead of
the 4GL UI functions.
Programming features
6-19
Data Access Layer (DAL)
abort.io() dal.set.error.message()
return(DALHOOKERROR)
db.update() dal.update()
db.delete() dal.destroy()
db.insert() dal.new()
If a function is used only in the DAL, you should move it to the DAL. If a
function is used in both the DAL and the UI, you can move it to the DAL (the UI
can call functions in the DAL but not vice versa). Alternately, you can store the
function in a separate DLL that is linked to both the UI and the DAL.
Session codes
The DAL does not recognize session codes (prog.name$) and so cannot evaluate
them. However, in the case where integrity checks must be session dependent, a
solution is to evaluate properties instead of session codes. For example, you
could identify a field or a combination of fields whose value(s) uniquely identify
the session. Or you could add a property to the object set and give this property a
value that is unique to the session.
Predefined variables
The predefined variable previous.choice is not supported in the DAL, as the
DAL does not recognize standard commands. Instead, the first argument in the
before.save.object() and after.save.object() hooks indicates if an insert or
update operation caused the save operation. Note that for the DAL, the copy
command is an insert operation.
The predefined variable before.update.check is not supported in the DAL. In
BaanERP, field checks are executed both after field input and before the database
operation. The programmer cannot influence when these checks are performed.
Note that in the CDAS, checking is programmed in the dal.set.property() hook
and not in the dal.after.save.object() hook.
Questions
It is not possible to ask for user input during the execution of DAL hooks. If
hooks contain conditions that depend on user input, set the condition before the
hook is called. Alternately, handle the user input and check the conditions after
completion of the database operations.
Programming features
6-20
Data Access Layer (DAL)
Messages
The DAL cannot display error messages directly. However, you can set an error
message in the DAL with the dal.set.error.message() method. The DAL can
notify the calling process of an error by returning the value DALHOOKERROR.
The process can then display the error message. Messages can be stacked before
they are retrieved by the UI.
Non-table fields
Only table fields are checked in the DAL. Checks for non-database fields must
still be programmed in the UI script.
Include files
When writing a Data Access Layer, you must include bic_dal. To use progress
indicators and Data Access Methods in your UI, you must include bic_dam.
Programming features
6-21
Data Access Layer (DAL)
Programming features
6-22
7 Multitasking and the GUI
Overview
The BAAN bshell provides the execution environment for BAAN applications.
Whenever a user logs on to the BAAN system, a separate bshell process is
activated for that user. So, when multiple users log on to the same BAAN
system, or when the same user logs on multiple times, multiple bshell processes
are activated on the execution platform.
The BAAN bshell provides a multitasking execution environment for BAAN
applications. Each bshell can execute and schedule multiple parallel processes.
So, it blocks individual processes only while they are waiting for user input, and
not while other processes are waiting for user input.
This section provides an overview of how processes and user interface
interaction are managed by the bshell.
The following diagram provides a schematic overview of the relationships
between the scheduler, process queues, and the display server.
Programming features
7-1
Multitasking and the GUI
NOTE The bshell is a single-threaded process. The complete bshell blocks when a
database action is performed by the database driver.
Bshell scheduler
The bshell scheduler is responsible for managing and scheduling processes. It
maintains four process queues, as follows:
n running queue
n blocking queue
n sleeping queue
n terminating queue
The scheduler keeps all processes in one or other of the above process queues,
depending on their current state.
Running queue
The scheduler schedules processor time only for those processes in the running
queue. It schedules each process in the running queue in turn, in order of priority.
Each scheduled process receives a number of ticks, and the execution of each
instruction costs the process a certain number of ticks. When the process has
used up all its ticks, the bshell schedules another process.
The scheduler always schedules the process with the highest priority.
When a process is started, it gets a default priority (this depends on its nice
value). While it is in the running queue, the process’s priority is incremented each
time that another process is scheduled. In this way, the process’s priority
increases until it has the highest priority in the running queue. It is then
scheduled. When a process has been scheduled, its priority returns to its default
value.
Blocking queue
When a process is waiting for input, the scheduler moves it from the running
queue to the blocking queue. So, the running queue contains only processes that
can be run. When a blocked process receives an event, it is moved back from the
blocking queue to the running queue.
Programming features
7-2
Multitasking and the GUI
Sleeping queue
Processes in the sleeping queue are suspended until some external action wakes
them again. Processes can be put in a sleeping state (and so in the sleeping
queue) only by the functions sleep(), suspend(), receive.bucket$(), and related
functions.
Terminating queue
When a process ends, it is stripped of almost all allocated data and moved to the
terminating queue. When the scheduler has scheduled another process to run, it
then ’cleans up’ the terminating queue. That is, it removes all processes except
zombie processes. A zombie process is a process that has ended but whose parent
process has not yet caught its exit signal.
Context switches
Each running process receives a number of ticks when it is scheduled. This is the
equivalent of a UNIX time slice. The execution of each instruction costs the
process a number of ticks. When the process has used up all its ticks, the bshell
schedules another process. The switch to another process is referred to as a
context switch.
Programming features
7-3
Multitasking and the GUI
When this mechanism is enabled, the bshell assigns bonus ticks to a process
when it locks a database record (note that a lock is applied when the first update,
insert, or delete is performed by a database transaction) . This means that the
process is not scheduled out before the lock is released (the lock is released when
the transaction is committed or aborted).
You can configure the bonus tick mechanism by means of environment variables
or user resources.
User resource Environment variable Value
bonus_enable BSE_BONUS_ENABLE 0 bonus ticks off
(default)
1 bonus ticks on
bonus_timeslice BSE_BONUS_ The number of bonus ticks to
TIMESLICE assign to a process. The default
is 1073741824.
bonus_timeout_ BSE_BONUS_ 0 Warning mechanism off.
warning TIMEOUT_WARNING
1 Warning mechanism on. A
warning message is
displayed when a process
is about to loose its time
slice. The message is also
displayed when a context
switch is forced.
2 This is similar to 1, except
that when the object is in
debug mode, the process
stops and the debugger
points to the next
instruction.
3 This is similar to 2, except
that the process is aborted.
Programming features
7-4
Multitasking and the GUI
Events
BaanERP programs are designed to respond to events. Usually, they consist of a
main loop that waits for events to occur. When an event occurs, the program
performs the appropriate actions to process the event. It then returns to its
waiting state.
Event types
There are four broad categories of events, as listed below. For a full list of
event types, see Chapter 17, Events, in U7167A US BaanERP Tools:
Functions reference.
n User action events.
Most of the events that occur in a BAAN application relate to user
interaction. When a user performs an action in the user interface (for
example, clicking the mouse or pressing a keyboard key), this generates an
event.
n Timer events.
A process can start a timer that sends an event to the calling process at
specified intervals. See Chapter 46, Timers, in U7167A US BaanERP Tools:
Functions reference.
n Client events.
A process can send client events to another process by using the send.event()
function. The sending and receiving processes can determine their own
protocol.
n Bucket message events.
A process can broadcast bucket message events to other processes by using
the bms.send() function.
Note that functions such as keyin$() and data.input() are based internally on
events.
Event flow
When a UI object generates an event, the display server sends that event to the
bshell. The bshell distributes received events to the event queues of the
appropriate process groups; note that events are sent to process groups and not
individual processes. The bshell never requests events; the display server always
acts independently.
Programming features
7-5
Multitasking and the GUI
When one of the processes in the bshell requires input, the bshell checks whether
any event is present in the event queue of the process group to which the process
belongs. If there are no events in the event queue, it checks the connection
between the bshell and the display server. If it finds events there, it distributes
them to the appropriate process groups.
Event masks
A process can set the event mask of a UI object in order to specify the types of
events in which it is interested; the object then generates only events of these
types (see the select.event.input() function). Normally, event masks are
automatically set for keyboard and mouse events. However, programmers should
not assume any default settings for an event mask. Note that the following event
types are always selected and cannot be masked: client events, timer events,
bucket message events.
Event functions
BAAN Tools provides the following functions for handling events:
n next.event( event )
n peek.event( event )
n pending.events( )
n send.event( event )
n select.event.input( object_id, mask )
Event arrays
The event argument included in the next.event(), peek.event(), and send.event()
functions consists of an array of longs (of size EVTMAXSIZE) that contains
details of the incoming or outgoing event. You retrieve the contents of an event
array by using the set of parameters defined for the particular event type. See
“Event array parameters” in Chapter 17 in U7167A US BaanERP Tools:
Functions refence.
Programming features
7-6
Multitasking and the GUI
Sample code
The following example illustrates the basic principle of event handling that is
used by almost every event driven program.
#include <bic_event>
function main_event_loop()
{
long event( EVTMAXSIZE )
Programming features
7-7
Multitasking and the GUI
For example, when retrieving information that does not change, you can store the
data in variables and retrieve it from those variables instead of sending queries to
the display server.
The following example illustrates the use of requests, inquiries, and replies:
#include <bic_gpart>
Programming features
7-8
Multitasking and the GUI
Process groups
A process group is a group of related, interdependent processes. One process is
the group leader. Child processes are started by the leader or by one of its
children. All processes belong to a process group.
The following are some of the characteristics of process groups:
n Each process group has its own event queue. Events are sent to the process
group, not to individual processes.
n When one process within a group starts a child process, the child process is
automatically placed in the same process group as its parent. However, you
can use the function set.pgrp() to place the process in a different process
group.
n When a process is killed or ended, its parent is automatically awakened,
unless the parent and child are in different groups.
n You use the grab.mwindow() function to set the process group to which a
main window sends its events. After calling this function, all events that
occur in the main window are sent to the specified process group.
Main windows
A main window acts as the frame window for both sessions and 3GL
applications. It is used for starting processes and for creating graphical and
character windows. It is not used directly for handling user input or displaying
program output. Usually, a main window consists of a border, title bar, menu bar,
status area, control menu box, sizing controls, and a work area. The objects used
by an application for user interaction are created within the work area of a main
window and are managed by that main window.
Each process can have zero, one, or more main windows.
Programming features
7-9
Multitasking and the GUI
Programming features
7-10
Multitasking and the GUI
A process with the same ID as its process group is referred to as the group leader.
For the group leader, the predefined variable background is set to FALSE, For
child processes, this variable is set to TRUE.
A process group keeps track of the number of processes that belong to it. When
no processes remain in the group, the group is automatically destroyed. You can
destroy all processes in a particular group simultaneously by calling kill.pgrp().
Programming features
7-11
Multitasking and the GUI
The code for disconnecting a child process from its parent can be included either
in the parent process or in the child process. In the following example, it is
included in the parent process.
old.mwindow = current.mwindow()
new.mwindow = create.mwindow( title, mode, flags)
change.mwindow( new.mwindow )
child.pid = act.and.sleep( program.name, arglist )
if child.pid then
set.pgrp( child.pid, child.pid )
grab.mwidow( new.mwindow, child.pid )
reactivate( child.pid )
endif
change.mwindow ( old.mwindow )
destroy.mwindow( new.mwindow )
In this example, the parent process first creates a new main window for the child
process. It then starts the child process and calls set.pgrp() to place the child
process in a different process group. By specifying the same ID for the process
and the process group in the set.pgrp() call, a new process group is automatically
created with the same ID as the process. The process becomes the leader of the
new process group. The parent process then calls grab.mwindow() to link the
new process group to the new main window.
Programming features
7-12
Multitasking and the GUI
In this example, it is important to start the child process with act.and.sleep() and
to reactivate the process only after it has been placed in the new process group. If
the process is started with activate(), and a context switch occurs immediately
after the child process is started, then the process would be scheduled with the
incorrect process group.
Note that if a process is moved to another process group, it will be impossible to
switch it back to the original group if that group is destroyed in the meantime.
When a parent process issues a wait() call but is ignoring child signals, child
processes exit without any action by the parent. They exit, send an exit signal to
the parent, and are removed. The parent process blocks until it receives an exit
signal from the last process. The exit value and process ID of the last child are
returned in the return value and prodess_id argument respectively of the wait()
function.
Programming features
7-13
Multitasking and the GUI
When a parent process issues a wait() call and is not ignoring child signals, the
exit signal of every child process is caught by the wait() function (including exit
signals from children in other process groups). So, each child waits after exiting
until its parent process calls the wait() function. While it is waiting for the parent
process to catch its exit value, the child process becomes a zombie process. It is
placed in the terminating process queue, but is not removed until the parent
catches its exit signal.
Programming features
7-14
Multitasking and the GUI
Note that if a parent ends while some of its children are zombie process, those
children are removed automatically.
Programming features
7-15
Multitasking and the GUI
Programming features
7-16
8 Dynamic-link libraries
Overview
BaanERP Tools supports the use of dynamic-link libraries (DLLs). A DLL
consists of a library of functions that are compiled, linked, and stored separately
from the processes that use them. The functions are resources that can be shared
by multiple programs that are running concurrently. Only one copy of the DLL
needs to be present in memory. Each program that uses the DLL links to it at
runtime, at the time it calls one of the DLL’s functions.
For example, consider the sprintf$() function. This is a very common function,
used by many programs. Instead of including a copy of the function in each
program that uses it, you can program the function in a separate DLL. Multiple
programs can then share this one copy of the function, by linking to the DLL at
runtime.
The following are some of the benefits of using DLLs:
n Instead of programming common functions in each program that uses them,
you can program the functions in one or more DLLs. The code can then be
shared by all the programs that use it. By implementing DLLs in BaanERP
applications, you can reduce the size of objects to a minimum, as the standard
program is not merged with each 4GL program script.
n You can upgrade a function within a DLL without recompiling all the
applications that use it.
n You can upgrade an application without recompiling all the DLLs it uses.
n A DLL is loaded only when required. It is also loaded only once, though
multiple programs can share its code.
The following sections describe how you handle DLLs.
Programming features
8-1
Dynamic-link libraries
Function declarations
For functions programmed within a DLL to be accessible to other programs, they
must be declared as external functions – that is, they must be declared with the
keyword EXTERN.
For example:
function extern long funct_a( long arg )
{
.....
}
Functions declared without the EXTERN keyword are local functions. They are
accessible only within the program in which they are declared. A DLL usually
contains both local and external functions.
External variables
External variables are declared outside the functions in a script, with the
EXTERN keyword. They are known within all DLLs in the process in which
they are declared. For example:
extern long var_2
Database fields
Database tables are declared as follows:
table t<table_name>
Declaration of a table implies declaration of all its fields also. Though a table
declaration does not include the EXTERN keyword, tables fields are known
within all DLLs in the process in which they are declared. When one DLL in a
process reads a record, the values of the record fields are shared by all DLLs in
the same process.
Programming features
8-2
Dynamic-link libraries
Dynamic linking
DLLs can be linked to a program script either at compile time or at runtime.
Programming features
8-3
Dynamic-link libraries
The are two ways to compile the libraries and program script:
n Use the BaanERP Tools. Choose the Compile option in the sessions
"Maintain Libraries" and "Maintain Program Scripts".
n Use the bicx.x compiler (where x.x is the bhsell version). For example:
$ bic6.2 dll1 -o odll1
$ bic6.2 dll2 -o odll2
$ bic6.2 dll3 -o odll3
$ bic6.2 <program> -o<object> -d odll1:odll2:odll3
Note that, at runtime, external functions are searched for in the order in which the
DLLs were supplied during compilation. In above example, dll1 is first.
Function overloading
When DLLs are dynamically linked at runtime, instead of at compile time,
function overloading is possible. This means that an external function contained
in a loaded DLL can be replaced by overloading another DLL that contains a
function with the same name and arguments.
You use the load_dll() function to load DLLs dynamically. When you call this
function, you can specify whether the DLL is to be overloaded or not. When
searching for an external function called by a program, the bshell always
searches in overloaded DLLs first.
Programming features
8-4
Dynamic-link libraries
The bshell searches the overloaded DLLs in reverse order. So, the DLL that
was overloaded last is searched first.
2 The first DLL where the function was found during compilation.
Programming features
8-5
Dynamic-link libraries
Next the bshell searches in DLLs specified using the following pragma
statement:
#pragma used dll <dll_object>
4 All dynamically loaded DLLs – that is, DLLs loaded by calling load_dll()
without the overload flag or with the overload flag set to 0. For example:
load_dll(dll_object, 0)
The bshell searches the loaded DLLs in the order in which they were loaded.
So, the DLL that was loaded first is searched first.
Note that you can change the search order of dynamically loaded DLLs by
calling load.dll() for a loaded DLL and changing the value of the overload
flag.
Script code
function main()
{
#ifdef DEBUG
if ( debug flag ) then
| Load dynamically DLL 'dll_new' to
| overload the DLL 'dll'
load_dll("odll_new", 1)
| Argument '1' means overload
endif
#endif
dll_function()
}
Programming features
8-6
Dynamic-link libraries
dll code
function extern dll_function()
{
...
}
dll_new code
function extern dll_function()
{
...
}
Syntax
bic_infox.x [-aidshwcV] [-eu] [-f[flags]] object
Options
-a Show all available object information (default).
-I Show instructions in object (Disassembler). This is only possible
when the object is compiled with the debug option.
-d Show used DLLs and where the external functions used are
defined.
-s Show list of used variables, (global) functions, string constants, and
double constants.
-h Show Object header.
-w Show #ident <strings>.
-c Check checksum.
exit(0) ok
exit(1) corrupted
Programming features
8-7
Dynamic-link libraries
Combining -e and -u displays the description of the object and the descriptions
and prototypes of all external functions within the object (see below).
Programming features
8-8
Dynamic-link libraries
Example
dllusage
This is the object description.
enddllusage
Runtime errors
The following runtime error message is displayed when a script calls a function
that has been removed from the DLL and only the DLL has been recompiled:
Dynamic Link Failure function %s
The following runtime error messages are displayed when a function’s arguments
are changed within a DLL without recompilation of programs that call the
changed function:
Arg error <function name>(<argument name>) type ...
expected ...
or
Illegal number of args (%d) for function %s expected %d
Programming features
8-9
Dynamic-link libraries
Programming features
8-10
9 The BAAN debugger
Overview
The BAAN debugger is an interactive statement interpreter that enables you to
control and test the execution of a program. Its principal features include:
n Simultaneous program execution and display of debug information
n Source instructions and debug information are displayed in their own
windows, separate from the application
n Source instructions are displayed in a window that you can move and resize
n On non-graphical displays, debug information is displayed in screen columns
81 to 132
n The debugger supports variable tracing during program execution (that is, all
changes to the values of specified variables are displayed during program
execution)
n The debugger is fully symbolic – machine addresses are not used
n The debugger is fully integrated with the bshell.
The debugger works only with source programs that have been compiled with the
debug option (-l in the case of the BAAN Compiler). When you start such a
program, two additional windows are displayed. One displays the source code
being executed (the line currently being processed is highlighted). The other is a
command window where you input debugger commands and where command
results and error messages are displayed.
For information about other debug facilities, the “Logic Server” section in the
BaanERP Tools Technical Manual.
Commands
Debugger commands consist of from one to three words; the words can be
separated from each other by one or more spaces. The assignment command is an
exception. Here the variable and the value to be assigned are separated by a ':='
sign. Most commands require a line number and/or a source name. If no source
name is specified, the default is the current source.
Programming features
9-1
The BAAN debugger
When you start the debugger for an object, the source used by the debugger is
first searched for by using the directions in the file fdx.x.<pack.comb.> (where
x.x is the bshell version), then it is searched for in the $BSE/tmp directory, and
finally in the current directory.
Command Action
b [[source] line_number] Set a break point on the current or specified
line of the current or specified source. The
line is highlighted.
Note that you cannot set break points in
included parts in a source. Instead the break
point must be set in the included file.
B [source] Display all set break points in the current or
specified source.
c [number] Continue (execute the source) up to the next
break point. If you specify a number, the
debugger skips that number of break points.
The executed source lines are not displayed.
C [number] Same as ’c’, except that the executed source
lines are displayed.
cc Change the size of the command window.
This is valid only when application and
debugger are in the same window.
cs Change the size of the source window. This is
valid only when the application and debugger
are in the same window.
d [source line_number] Delete the break point on the specified line
number in the source. If you do not specify a
line number, the debugger provides the
opportunity to interactively delete any break
point in the current source file.
D [source] Delete all set break points in the specified or
current source.
delete all Delete all traces and stop instructions.
delete number Delete a specified trace or stop instruction.
Programming features
9-2
The BAAN debugger
Command Action
ds Delete the source window.
dd Generate a dump of the data dictionary.
<expression> Execute the specified expression.
f [noarg|noname] Display stack trace (present nesting of
[number] functions), with the arguments of the
functions. If you specify a number, only that
number of nestings is displayed.
noarg only the names of functions are
displayed
noname arguments are displayed but not
their names
fdebug Show the open tables on the command
window.
Fdebug Print the open tables to the spooler.
g [source] line_number Continue program execution at the specified
line number (goto).
help (or ?) Start the Help Viewer for debugger options.
instr Generate a symbolic dump of the object.
l Display the full list of program variables.
L Display the list of program variables that
have a value, and display their current values.
To stop displaying the contents of an array,
enter ’n’ at the question ’More ?’.
lp Print the output of the ’l’ command.
Lp Print the output of the ’L’ command.
mem Generate a dump including information about
the memory allocated.
p Go to the source line currently being
processed (this is useful after the view or seek
command). The line is indicated by a greater
than (>) sign before the line number.
Programming features
9-3
The BAAN debugger
Command Action
q Exit the debugger (quit).
return Continue execution until the end of the
current function.
s [number] Execute the program step by step, the
specified number of instructions at a time
(default is 1). During execution, the
intermediate source lines are not displayed.
S [number] Similar to ’s’, except that a function call is
executed as a single statement.
slow [number] Reduce the rate of running source code. The
maximum number is 100; the minimum (and
default) number is 0.
split number Split the command and source window. The
specified number is the last line of the
command window. This is often used after
resizing the Debugger window.
status Display traced variables and/or stop
[trace|stop|number] instructions. If you specify a number, only
that traced variable or stop instruction is
displayed.
stop if <expression> Stop execution when expression is True.
stop in <function> Stop execution when function is entered.
sym Generate a dump of the symbol table.
trap off Disables ‘trap on’. This command is available
only when the bshell was started with the -
dbgcpu flag.
trap on The debugger stops after execution of every
function call. This command is available only
when the bshell was started with the -
dbgcpu flag.
Programming features
9-4
The BAAN debugger
Command Action
t variable Trace the specified variable during program
execution. The execution of the program
stops every time the value of the variable is
changed. You cannot trace array variables or
common variables.
T variable [value] Same as ’t’, except that program execution is
not stopped when the variable changes. If you
specify a value, execution stops when the
variable gets that value.
u [variable] Stop tracing the specified variable. If no
variable is specified, you can stop tracing
each variable interactively.
U Stop tracing all variables currently being
traced.
v [source] line_number Display a specified source line in the source
window (view). If line_number is greater than
the total number of lines, the last line is
displayed.
v {+-} number Shift the display to the source line that is
number lines before or after the current
source line.
/pattern Seek a matching text pattern in the current
source and display that line.
[function.]variable Display the value of a specified variable. If
[/option] you specify a function, the value of the local
variable of that function is displayed.
Otherwise, the value of the variable of the
current function or the global variable is
displayed. If a variable has no value (empty
string or zero number), the value is not
displayed.
/option can have the following values:
Programming features
9-5
The BAAN debugger
Command Action
/
Use to display the value of a variable that has
the same name as a Debugger command. For
example, ‘b/’ displays the value of variable b.
/d
Print the flags of the variable and the
dimension for arrays.
/D
Display the number of bytes allocated in a
long or double variable. Display the number
of bytes for one element in a string array.
The following options are useful for record
buffers and binary data. They display the
value of a string variable with its full declared
length, regardless of NUL characters.
/x
NUL characters are displayed as ‘^@’.
/X
Characters with values 0 to 31 are displayed
as ‘\x<value in hex>’.
/b
All characters are displayed as ‘\x<value in
hex>’.
variable := value Assign a value to a variable. The value can
be:
n A string constant or expression
n A numeric constant or expression
n A variable name
vi Activate the vi editor for the current source at
the current source line. Changing the source
has no influence on the source displayed by
the debugger in the source window.
width value Change the width of command and source
window. You can specify any value in the
range 80 to 132.
Programming features
9-6
The BAAN debugger
Command Action
<Ctrl>D/<Ctrl>U Page down or up in source.
Command Action
<Esc> Toggle between normal and history mode.
<Arrow up>/ <Arrow In history mode, these display previously
down> executed commands on the command line. In
normal mode, these move the cursor through
the source.
Programming features
9-7
The BAAN debugger
Programming features
9-8
10 Errors
Notes
To retrieve errors with error codes greater than 1000, subtract 1000 from the
error number. The result is the database error code. For example, the error code
1510 represents the database error code 510 (that is, 1510 – 1000).
When a fatal error occurs, information about the error is stored in the log files in
the directory $BSE/log. For example, if bdbpost6.2 causes an error, this is
reported in the file log.bdbpost6.2.
UNIX errors
1 EPERM Not owner
This indicates an attempt to modify a file that cannot be
modified, except by its owner or by a super user. This is
also generated when ordinary users attempt an action that
only a super user is permitted to carry out.
2 ENOENT No such file or directory
This occurs when a specified file name should exist but
does not, or when one of the directories in a path name
does not exist.
3 ESRCH No such process
This occurs when a specified process cannot be found.
Programming features
10-1
Errors
Programming features
10-2
Errors
Programming features
10-3
Errors
Programming features
10-4
Errors
Programming features
10-5
Errors
Database errors
100 EDUPL This indicates that a duplicate value exists.
101 ENOTOPEN This indicates that the specified table is not
open.
102 EBADARG This indicates that an illegal argument has
been specified.
103 EBADKEY This indicates that an Illegal key description
has been specified. Use the bdbpre and
bdbpost tools to resolve.
107 ELOCKED This indicates that the specified record is
locked. You can either wait until the lock is
released or you can remove the lock yourself.
108 EKEXISTS This indicates that the specified key already
exists.
110 EENDFILE This indicates that the end of file has been
reached.
111 ENOREC This indicates that no record was found that
matches the query criteria.
112 ENOCURR This indicates that there is no current record.
113 EFLOCKED This indicates that the table is locked. You
can either wait until the lock is released or
you can remove the lock yourself.
201 EROWCHANGED This indicates that the record was changed
after a delayed lock.
202 EDBLOCKED This indicates that the database is locked.
You can either wait until the lock is released
or you can remove the lock yourself.
203 ETRANSACTIONON This occurs when you attempt an action that
is not allowed within the transaction.
204 EISREADONLY This indicates that the transaction is read
only.
Programming features
10-6
Errors
Programming features
10-7
Errors
Programming features
10-8
Errors
Programming features
10-9
Errors
Programming features
10-10
11 Known limits
Reports
n Sorting doubles correct to 6 decimal places
n Maximum 253 fields on a report (including array elements)
Bshell
n Maximum string buffer size is 4K – be careful when concatenating strings
with '&' sign
n Maximum function stack depth is 75
Bic
n Maximum 255 arguments per function
n Maximum 32K variables per compilation
n Maximum BRANCH of 32K (BRANCH refers to the amount of generated
code per function, including macros etc.)
SQL
n Maximum of 50 AND conditions within WHERE clause – otherwise the
following error message appears:
"Stack overflow [QueryId = XX]"
Tables
n Maximum record length is 3072 bytes
n Maximum number of fields is 1024
n Maximum field length is 3072 bytes
Programming features
11-1
Known limits
Indexes
n Maximum index length is 120 bytes
n Maximum number of fields is 32 (no combined fields)
n Maximum number of index parts is 8
Programming features
11-2
12 ASCII table (ISO 8859-1)
0 00 128 80
^A 1 01 129 81
^B 2 02 130 82
^C 3 03 131 83
^D 4 04 132 84
^E 5 05 133 85
^F 6 06 134 86
^G 7 07 135 87
^H 8 08 136 88
^I 9 09 137 89
^J 10 0A 138 8A
^K 11 0B cf$(0) 139 8B
^L 12 0C cf$(1) 140 8C
^M 13 0D cf$(2) 141 8D
^N 14 0E cf$(3) 142 8E
^O 15 0F cf$(4) 143 8F
^P 16 10 cf$(5) 144 90
^Q 17 11 cf$(6) 145 91
^R 18 12 cf$(7) 146 92
^S 19 13 cf$(8) 147 93
^T 20 14 cf$(9) 148 94
^U 21 15 cf$(10) 149 95
Programming features
12-1
ASCII table (ISO 8859-1)
^V 22 16 cf$(11) 150 96
^W 23 17 cf$(12) 151 97
^X 24 18 cf$(13) 152 98
^Y 25 19 cf$(14) 153 99
^Z 26 1A cf$(15) 154 9A
ESC 27 1B 155 9B
^\ 28 1C 156 9C
^] 29 1D 157 9D
^^ 30 1E 158 9E
^_ 31 1F 159 9F
SP 32 20 NBSP 160 A0
! 33 21 ¡ 161 A1
" 34 22 ¢ 162 A2
# 35 23 £ 163 A3
$ 36 24 ¤ 164 A4
% 37 25 ¥ 165 A5
& 38 26 ¦ 166 A6
' 39 27 § 167 A7
( 40 28 ¨ 168 A8
) 41 29 © 169 A9
* 42 2A ª 170 AA
+ 43 2B « 171 AB
, 44 2C ¬ 172 AC
- 45 2D SHY 173 AD
. 46 2E ® 174 AE
/ 47 2F ¯ 175 AF
Programming features
12-2
ASCII table (ISO 8859-1)
0 48 30 ° 176 B0
1 49 31 ± 177 B1
2 50 32 ² 178 B2
3 51 33 ³ 179 B3
4 52 34 ´ 180 B4
5 53 35 µ 181 B5
6 54 36 ¶ 182 B6
7 55 37 · 183 B7
8 56 38 ¸ 184 B8
9 57 39 ¹ 185 B9
: 58 3A º 186 BA
; 59 3B » 187 BB
< 60 3C ¼ 188 BC
= 61 3D ½ 189 BD
> 62 3E ¾ 190 BE
? 63 3F ¿ 191 BF
@ 64 40 À 192 C0
A 65 41 Á 193 C1
B 66 42 Â 194 C2
C 67 43 Ã 195 C3
D 68 44 Ä 196 C4
E 69 45 Å 197 C5
F 70 46 Æ 198 C6
G 71 47 Ç 199 C7
H 72 48 È 200 C8
I 73 49 É 201 C9
Programming features
12-3
ASCII table (ISO 8859-1)
J 74 4A Ê 202 CA
K 75 4B Ë 203 CB
L 76 4C Ì 204 CC
M 77 4D Í 205 CD
N 78 4E Î 206 CE
O 79 4F Ï 207 CF
P 80 50 Ð 208 D0
Q 81 51 Ñ 209 D1
R 82 52 Ò 210 D2
S 83 53 Ó 211 D3
T 84 54 Ô 212 D4
U 85 55 Õ 213 D5
V 86 56 Ö 214 D6
W 87 57 × 215 D7
X 88 58 Ø 216 D8
Y 89 59 Ù 217 D9
Z 90 5A Ú 218 DA
[ 91 5B Û 219 DB
\ 92 5C Ü 220 DC
] 93 5D Ý 221 DD
^ 94 5E Þ 222 DE
_ 95 5F ß 223 DF
` 96 60 à 224 E0
a 97 61 á 225 E1
b 98 62 â 226 E2
c 99 63 ã 227 E3
Programming features
12-4
ASCII table (ISO 8859-1)
d 100 64 ä 228 E4
e 101 65 å 229 E5
f 102 66 æ 230 E6
g 103 67 ç 231 E7
h 104 68 è 232 E8
i 105 69 é 233 E9
j 106 6A ê 234 EA
k 107 6B ë 235 EB
l 108 6C ì 236 EC
m 109 6D í 237 ED
n 110 6E î 238 EE
o 111 6F ï 239 EF
p 112 70 ð 240 F0
q 113 71 ñ 241 F1
r 114 72 ò 242 F2
s 115 73 ó 243 F3
t 116 74 ô 244 F4
u 117 75 õ 245 F5
v 118 76 ö 246 F6
w 119 77 ÷ 247 F7
x 120 78 ø 248 F8
y 121 79 ù 249 F9
z 122 7A ú 250 FA
{ 123 7B û 251 FB
| 124 7C ü 252 FC
} 125 7D ý 253 FD
Programming features
12-5
ASCII table (ISO 8859-1)
~ 126 7E þ 254 FE
DEL 127 7F ÿ 255 FF
Programming features
12-6
13 Index
3 C
3GL programming language..... 1-1, CASE statement....................... 2-23
............................................... 2-1 combined fields......5-23, 5-24, 5-25
constants ................................ 2-3 commands..................3-8, 3-9, 3-12
expressions and operators.... 2-16 common variables........... 2-14, 2-15
iterations .............................. 2-25 compiler ................................... 2-45
overview ................................ 2-1 conditional compiling .............. 2-41
transfer of control ................ 2-21 constants ......................2-3, 2-4, 2-5
variables................................. 2-5 context switches......................... 7-3
vocabulary ............................. 2-1
D
4
DAL overview .................... 6-1, 6-2
4GL programming features Data Access Layer
automatic import of variables ...... communication with STP and
......................................... 3-27 CDAS .............................. 6-18
event sections......................... 3-2 data access methods............. 6-16
flow of standard program..... 3-21 hooks...................................... 6-5
overview ................................ 3-1 object hooks.................... 6-7, 6-8
property hooks ....................... 6-6
A
property methods ................. 6-17
after.commit.transaction() ....... 6-15 query extensions .................. 6-17
after.destroy.object()................ 6-12 terminology............................ 6-3
after.get.object() ...................... 6-10 transition issues (BAAN IV to
after.save.object() .................... 6-14 BaanERP) ........................ 6-18
arithmetic operators ................. 2-17 UI DAL and STP interaction . 6-3
ASCII table.............................. 12-1 database handling
assignment operator................. 2-20 error handling ...................... 5-39
hints for using db.retry.point 5-43
B
hints for using SQL.............. 5-41
based variables......................... 2-12 overview ................................ 5-1
before.destroy.object()............. 6-12 transaction handling............... 5-5
before.get.object()...................... 6-9 using program variables....... 5-15
before.open.object.set() ............. 6-9 debugger .................................... 9-1
before.save.object() ................. 6-13 debugger commands .................. 9-1
debugger mouse actions............. 9-7
delayed locks .................... 5-7, 5-31
Programming features
13-1
Index
Programming features
13-2
Index
Programming features
13-3
Index
Programming features
13-2