guide to the navision al dbms

202
Guide to the NAVISION AL & DBMS This guide includes the following three documents which have previously been released as individual manuals: AL Programmers Guide AL Reference Guide The NAVISION DBMS

Upload: mahadev-subramani

Post on 22-Dec-2015

270 views

Category:

Documents


13 download

DESCRIPTION

Guide to the Nav DBMS

TRANSCRIPT

Page 1: Guide to the Navision Al Dbms

Guide to the NAVISIONAL & DBMS

This guide includes the following three documents which have previously been released as individual manuals:

AL Programmers GuideAL Reference GuideThe NAVISION DBMS

Page 2: Guide to the Navision Al Dbms

This publication is subject to change without notice and does not represent any commitment on the part of Navision Software a/s.

Navision Software a/s assumes no responsibility for any faults or shortcomings in this publication.

The software described is supplied under license and must be used and copied in accordance with the enclosed license terms and conditions.

According to existing Danish copyright legislation, it is against the law to reproduce any part of this publication in any form or by any means, without the permission of Navision Software a/s.

Navision is a registered trademark of Navision Software a/s.

Microsoft, Windows and Windows NT are trademarks of Microsoft Corporation.

Paintbrush is a registered trademark of Zsoft Corporation.

Copyright © 1996 Navision Software a/s. All rights reserved.

ISBN 87-7849-064-2Doc.no. W1-XU-BAG1-CB08-X

Published by Navision Software a/s.Printed in Denmark 1996.

Page 3: Guide to the Navision Al Dbms

Table of Contents

Part 1, AL Programmers Guide 1

Examples and Notes 2Notation for Datatypes in Expressions 2

Typographical Conventions 2Compilation vs. Run Time Errors 3

Important Terms 3

Expressions in AL 4AL Data Types 5Constants 8

Elements in AL Expressions 8Variables 9Operators 13Operator Hierarchy 14Function Calls 15Compound Statements 16Conditional Statements 16

The AL Control Language 16Repetitive Statements 18EXIT Statements 20WITH Statements 21Comments in Programs 22

Type Conversion in Expressions 23Type Conversion Mechanisms 24Relational Operators 24Yes/No (Logical) Operators 27Introduction to Arithmetic Operators 27

Part 2, AL Reference Guide 37Typographical Conventions 38

AL Functions grouped by category 39Formatting of Numbers 126Formatting of Dates 127Formatting of Times 128Formatting of Strings 129

Page 4: Guide to the Navision Al Dbms

Part 3, The NAVISION DBMS 163

The Aim of This Document 164Physical vs. Logical Database 165

The Structure of the Database 165Logical Organization 166Fields and Records 167Tables 170The Key List 174Companies 175Special Database Fields 176

Important Tasks for the DBMS 179Data Integrity 179Database Security and Protection 187

Interfacing the DBMS 189Table Handles 189Current key 190Filters 191The DBMS Cache 193

Features for Increasing Performance 193The Commit Cache 194The Command Buffer 195

Appendix A, Sum Fields 197

Page 5: Guide to the Navision Al Dbms

AL Programmers Guide1Part

AL Programmers Guide 1

This document provides detailed information about the Application Language (AL). The aim is that this document should serve as a guide for the novice, and also as a handbook and refresher for the pro. The aim of this document is neither to teach the reader how to program, nor to introduce specific programming techniques. This means that a certain amount of knowledge about programming in other languages, for instance Pascal or C, is assumed.

Because AL, unlike most other 4GLs is very similar to commonly used programming languages, you’ll find the many Pascal books and other training aids a valuable resource as you create your own applications.

The following list outlines some of the most powerful properties of AL. The AL language:

• Performs automatic type conversion between related types (not only between numbers

• Includes pre-defined types like Date and Time

• Performs automatic attachment between database tables and records

• Includes standard functions for:

- Database access

- Date calculations

- Handling strings

- Handling windows and menus

- Access to the operating system

• Provides pre-defined types corresponding to the record layout in all the database tables

• Allows the use of a variable number of parameters in standard function calls

• Allows the use of nested comments in programs

• Performs automatic error handling.

This will also be the proper place to notify the reader of the following delimitations compared to languages such as standard Pascal:

• New data types cannot be defined

• There are maximum sizes for variables

• Arrays have a maximum of three dimensions

Page 6: Guide to the Navision Al Dbms

2 AL Programmers Guide

Typographical Conventions

This AL manual uses special typefaces to help you distinguish different types of text. Table 1 illustrates these conventions:

Examples and NotesIn this document you will find paragraphs starting with the word Example. These paragraphs provide examples related to the current context.

You will also find paragraphs starting with Note: . These paragraphs provide additional information about what measures the user must take in order to get the current operation to work properly. Often these paragraphs warns the user of errors that might occur.

Notation for Datatypes in ExpressionsAll valid expressions in AL can be evaluated into a unique result having a specific datatype. An expression like:

1204 + 123.46 - 45000

could (in this document) also be expressed in terms of the corresponding datatypes, that is:

Integer + Decimal No. - Long Integer

This notation will only be used when the focus is on the datatypes rather than on specific values. It is stressed that this notation is not a ‘real’ AL notation, but rather a notation which is intended to be used for descriptional purposes

Table 1: Conventions

Convention Applies to Examples

Monospaced Font AL code examples Number:= 6;

Times Font Normal text This is a sentence

Helvetica Font Table bodies Text in a table cell

ALL CAPSAL keywords when used in normal text and in AL code examples

...by using the MES-SAGE function...

TypographicalConventions

Page 7: Guide to the Navision Al Dbms

AL Programmers Guide 3

Important Terms

The aim of this section is to briefly discuss the following important terms:

• Compilation vs. run time errors

• Statements, expressions and operators

Compilation vs. Run Time ErrorsWhen you have written some new AL code the system tells you if there is an error in it at two points:

1. When you compile the AL code, the system checks the syntax of the code and displays a message if it finds an error. The system will not compile your pro-gram until the syntax is correct.

2. Although the syntax of your program is correct, the code might still contain errors. These are different from the compilation errors, as they only occur when the program is run. They violate restrictions imposed by the system. A typical run time error occurs if a function is called with an argument which is outside a valid range.

Statements, Expressions and Operators

Consider the following AL code sample:

Amount := 34 + Total;

This individual code line is also called a statement. Table 2 illustrates how the statement can be can broken into smaller elements.

The above discussion is only intended to serve as a brief introduction to some basic terms.

Table 2: Elements in a statement

Element Description

34 + Total

An expression. In this case the expression consists of an arithmetic operator (+), and two arguments (34 and Total), which also could be called sub-expressions. All valid AL expressions can be evalu-ated into a specific value

:=

The assignment operator. When the right-hand side expression has been evaluated into a value, this operator is used to assign (store) the value in the variable Amount

AmountThis is called a variable (or sometimes an identi-fier). Is used as a memory in order to stores values.

ImportantTerms

Page 8: Guide to the Navision Al Dbms

4 AL Programmers Guide

Expressions in AL

Understanding the concepts of expressions, is fundamental when programming in the AL language. This section describes expressions and how they are used.

An expression can be used as an argument to an AL function. Consider the AL statement below:

Date := DMY2DATE(31, 12, 1996);

This function takes three simple expressions as arguments, that is 31, 12 and 1996.

An AL expression is a group of characters that can include data values, variables, arrays, operators, and functions (which can be evaluated into a value). All valid AL expressions can be evaluated into a specific value which has an associated data type.

All expressions in AL are built from:

• Constants

• Variables

• Operators

• Functions

Depending on the expression the evaluation will lead to a value from one of the AL data types: Yes/No, Option, Integer, Long Integer, Decimal No., Date, Time, Text or Code.

Table 3 shows some typical expressions.

The first line shows a text string which is evaluated into itself. The second line evaluates into a concatenation of the two strings. The third line shows a decimal number, which is evaluated into itself. The expression in the fourth line contains a function, which with the given argument is evaluated into the number 7234. The last line shows a comparison between a variable and a numerical constant.

The above was just typical examples of how AL expressions evaluated into a value having some AL data type. The following section describes the AL data types in further detail.

a. The ABS function calculates the absolute value of the argument.

Table 3: Typical expressions

Expression Evaluates to...

'Welcome to Hawaii'; The string 'Welcome to Hawaii'

'Welcome' + ' to Hawaii'; The string 'Welcome to Hawaii'

43.234; The number 43.234

ABS(-7234) The number 7234a

len1 < 618; TRUE or FALSE depending on the value of len1

Expressions in AL

Page 9: Guide to the Navision Al Dbms

AL Programmers Guide 5

Expressions in AL

AL Data TypesThis section describes the data types used in AL. The data types are divided into three main categories, named: Simple Data Types, Composite Data Types and Descriptional Data Types.

Simple Data Types

The simple data types are fundamental when describing real world data in AL. The simple data types are also used as building blocks for the composite data types to be discussed in the following section.

Yes/No . Denotes a so-called Boolean data type. May have the values TRUE or FALSE.

Option . Denotes integers ranging from 0 to 255.

Integer . Denotes integers ranging from -32,767 to 32,767.

Long Integer . Denotes integers ranging from -2,147,483,647 to 2,147,483,647.

Decimal No. Denotes decimal numbers ranging from -10+63 to +10+63. The exponent ranges from -63 to +63. Decimal numbers are held in memory with 18 significant digits.

Date. Denotes dates ranging from January 1, 1980 to December 31, 2059. An undefined date is expressed as 0D. All dates have a corresponding closing date. The closing date for a given date is regarded by the system as a period following the given date, but before the next normal date, thus closing dates are sorted immediately after the corresponding normal date, but before the next normal date.

Time . Denotes a time. An undefined time is expressed as 0T. Any time in the range 00:00:00 to 23:59:59.999 is valid.

Text . Denotes a text-string. The maximum length of the string ranges from 1 to 132 characters. The length of a variable of type Text, corresponds to the number of characters in the text. An empty text string thus has the length 0.

Table 4, “Assignments of Text strings,” on page 5 illustrates some typical examples of text strings. In these examples it is assumed that the variable t is of the type Text and has the maximum length 6.

Note: in the context of the following two data types (Text and Code), it is important to distinguish between the maximum length of the string, and the actual length of the string. The maximum length can be seen as the upper limit for the number of characters in the string, while the actual length describes the number of characters used in the string.

Table 4: Assignments of Text strings

Assignment Results in...

t := 'AbC'; The variable t now contains 'AbC'.

t := '123456abx';Results in a run-time error, because the length (9) exceeds the maximum length (6).

Page 10: Guide to the Navision Al Dbms

6 AL Programmers Guide

Expressions in AL

Code . Denotes a special type of text string. When a given text is assigned to a code type variable, the text is transformed to uppercase, and furthermore any leading and trailing spaces are removed. The maximum length of a code type variable ranges from 1 to 132 characters. The length of a code type variable always corresponds to the number of characters in the text without leading and trailing spaces. Table 5 shows some typical examples of Code string assignments. In the examples it is assumed that the variable c has the type Code, and the maximum length 4.

Composite Data Types

Based on the simple data types described above, it is possible to define some data types with a more complex structure, such as Records and Arrays.

Record . A Record is a complex data type, which consists of a number of simpler elements. These are called fields. Each field can be used to store values of a certain data type. The fields are accessed using the record name, a dot and the field name. A record is typically used to hold information about a fixed number of properties. A typical example:

Assume that a company needs a convenient way to organize information about their employees. One way would be to register all relevant information in a table in a database. In this table the data for each employee could be stored in records containing appropriate fields, for example fields for Name, Age, Address e.t.c.

Array . Based on the simple data types and Records presented above, it is possible to create one, two-and three-dimensional variables. Each dimension of a variable can contain up to 999 elements. However, a variable must never be larger than 32 Kb. Arrays are always indexed from 1 to (and including) the size of the dimension(s). If one tries to index outside the range of the dimensions of an array, a run-time error occurs. Some typical examples of arrays:

Assume that I is a one-dimensional array variable of the Integer type, with the dimension 10.

• In order to index the first element, use I[1].

• In order to index the last element, use I[10].

Assume that D is an array variable of type Date with the dimensions 2x3x4. Then D has 24 elements.

• In order to index the first element, use D[1,1,1].

Table 5: Assignment of values to Code strings

Assignment Results in...

c := 'AbC'; The variable c now contains 'ABC'. The length is 3.

c := '1'; The variable c now contains '1'. The length is 1.

c := '';The variable c now contains '' (empty string). The length is zero.

c := ' 2 '; The variable c now contains '2'. The length is 1.

c := '1 2'; The variable c now contains '1 2'. The length is 3.

Page 11: Guide to the Navision Al Dbms

AL Programmers Guide 7

Expressions in AL

• In order to index the last element, use D[2,3,4].

Descriptional Data types

In order to describe the syntax of the AL-language, some additional data types are needed. It is important to stress that these are not real system data types, but only are used in this document for descriptional purposes.

Number . This data type denotes the union of the Option, Integer, Long Integer and the Decimal No. data types

String . This data type denotes the union of the Text and Code data

Table 6 summarizes the correspondance between the descriptional data types and the simple AL data types.

Table 6: The descriptional data types used in this manual

Numbers Option

Integer

Long Integer

Decimal No.

Strings Text

Code

Page 12: Guide to the Navision Al Dbms

8 AL Programmers Guide

Elements in AL Expressions

The previous chapter has introduced you to the notion of expressions and futhermore the data types used in AL was described. The aim of this chapter is to present the basic elements of AL expressions. In short the following sections will discuss the topics below:

• Constants

• Variables

• Operators.

• Functions

We start by defining ranges and properties of constants in AL.

ConstantsA constant is the simplest type of operand used in AL. The value of a constant cannot be changed during the execution of the code. Constants can be defined for each of the simple data types in AL.

Yes/No (Boolean) Constant . A Yes/No constant may either have the value TRUE or FALSE.

Integer Constant . An Integer constant may have a value between -32,767 and 32,767.

Long Integer Constant . A Long Integer constant has a value in one of the following intervals:

From -2,147,483,647 to -32,768 and

From 32,768 to 2,147,483,647

If the number is between -32,767 and 32,767, it is, as mentioned above, an integer.

Decimal No. Constant . A Decimal No. constant must contain a decimal point '.' and have at least one digit to the right of the decimal point (for example the digit '0'). A constant of type Decimal No. can be used to represent decimal numbers between -999,999,999,999,999.99 and 999,999,999,999,999.99 with 18 significant digits.

Date Constant . A Date constant is written as six digits followed by the letter 'D' (the date constant expressing 'undefined date' is, however, entered as '0D'). The six digits specify the date in the format MMDDYY.

Time Constant . A Time constant is written as nine digits followed by the letter 'T' (the 'undefined time' constant is, however, entered as '0T'). The nine digits specify the time in the format HHMMSS[.XXX], that is a 24 hour format with an optional part specifying thousandths.

Text Constant . A Text constant is a character string that is placed in apostrophes ('). '' indicates the empty text string.

Examples

Note : Before we define the valid ranges for the constants below, we have to warn the reader: the numbers 32,767; 2,147,483,647 and 999,999,999,999,999.99 below cannot be entered in the AL system using commas. The commas are only used to increase the legibility in this document. If numbers are entered in the AL editor using commas, a compilation error will occur.

Elements in ALExpressions

Page 13: Guide to the Navision Al Dbms

AL Programmers Guide 9

Elements in AL Expressions

Table 7 illustrates different types of AL constants.

VariablesThere are two types of variables in the AL system: User-defined variables and Implicit variables.

Variables are defined by the user when new AL code is implemented. These user-defined variables are local to the AL module for which they have been defined. These variables can be used to store information at run time, and the values can be changed as desired.

Furthermore, a number of predefined variables are provided by the system. These variables are automatically maintained by the system and are called Implicit variables

The implicit variables can in many respects be used just like normal user defined variables, but as the values of the implicit variables are maintained automatically by the system, some restrictions should be observed.

The running system will sometimes enter a code module, for example entry-processing code for a table. Before the module is entered, the system has automatically assigned values to the associated implicit variables, and in the module (in the AL triggers and the local functions) the values of these variables can be used.

During the execution of AL triggers and local functions, the implicit variables can be used just like normal variables (new values can be assigned to them) that is, the values of the implicit variables are not updated by the system while the AL code is being executed, but only before the module is entered. Some other important properties are best explained using an example:

Example

A typical implicit variable is CursorPos, which describes the position of the cursor. This implicit variable will be available in the AL triggers and the local functions in some code modules, and can be read and changed as desired by the user. But although the value of the implicit variable can be changed by the AL code, the old value of CursorPos will be lost the next time the module is entered,

Table 7: Examples of AL constants

Constant Description

TRUE Yes/No (Boolean) constant

231 Integer constant

50000 Long Integer constant

-23.7 Decimal No. constant

122196D Date constant (December 21, 1996)

141230T Time constant (the time 14:12:30)

'ABC’ String constant

Page 14: Guide to the Navision Al Dbms

10 AL Programmers Guide

Elements in AL Expressions

as the implicit variables are automatically maintained by the system.

Furthermore it is also important to understand that the value in an implicit variable like CurserPos does not propagate backwards, in other words the user cannot use the implicit variable CurserPos to set the position of the cursor.

Variable Names

Variable names must be unique, that is, two user defined variables with the same name are not allowed in an AL module. Furthermore you cannot have user defined and implicit variables with the same name. Uppercase and lowercase letters are interpreted in the same way, that is Smith and SMITH are taken to be referring to the same variable. In standard Pascal notation a variable name (an identifier) can only be written as an unbroken word. This notation is extended in AL; here it is also possible to use special characters (for example spaces) in a variable name.

Observe the following basic restrictions:

• The maximum length of a variable name is 20 characters.

• A variable name must not correspond to an AL function name or to any reserved word. Please note that this rule applies both for uppercase and lowercase spellings, for example neither BEGIN nor begin are valid.

All ASCII characters are valid in variable names, except the following:

• Control characters (ASCII 0-31, 255)

• The characters @ (ASCII 64) and " (ASCII 34)

When using a variable name, observe the following:

• The characters cannot be combined freely. Normally the first character will be:

- a letter in the range: a..z, A..Z (ASCII 97-122, 65-90), or

- an underscore (ASCII 95).

...followed by a maximum of 19 characters, which can be either:

- a letter a..z , A..Z (ASCII 97-122, 65-90)

- an underscore (ASCII 95), or

- digits in the range 0..9 (ASCII 48-57)

As already mentioned, it is also possible to include one or more special characters (spaces e.t.c) in a variable name in AL, but if the user desires to use variable names which contain one or more special characters, then the entire variable name must be put in double quotes.

As long as a variable name is encapsulated in double quotes, it can contain any mix of letters, digits and special characters.

Examples

• The following variable names are valid:

• Customer

• StockGroup1

Note : The double quotes are not part of the variable name, but are necessary in order to avoid a compile-time error.

Page 15: Guide to the Navision Al Dbms

AL Programmers Guide 11

Elements in AL Expressions

• "1st AddressLine"

• "Purchase/Sales"

• "Sales In GBP"

• " YesCrazy Name1Ñ3"

...while the following variable names are invalid:

• 34467

• 23"Tubes

• Stock Group4

• "Sale"s in GBP"

• @-Names

• END

Initialization

Internal variables are automatically initialized before an AL module is executed. A Yes/No variable is set to FALSE, Number type variables are set to the default value zero, while strings (Text and Code) are initialized to the value’’ (the empty string). Date and Time variables are set to respectively the undefined time 0T and the undefined date 0D.

As previously mentioned the system automatically handles the implicit variables. This also includes the necessary initialization. This means that no actions are required by the user before the implicit variables can be used.

Assignment and Type Conversion

Assignment of values can be performed in one of two ways.

1. As parameter assignment, for example FUNCTION(Expression). The result-ing datatype of the evaluation of the expression must correspond to a specific datatype or have a type which can be converted automatically to the correct type. (For a detailed discussion about evaluation and type conversion in expressions, please see “Type Conversion in Expressions” on page 23.)

2. By using the assignment operator ':=', for example Variable := Expression. Generally, the resulting datatype of the evaluation of the right-hand side expression1 must be of the same type as the variable (left operand) or have a type which can be converted automatically to the type of the left operand.

Automatic type conversion in assignments automatically takes place when:

1. A parameter in a function call does not have the correct type. This occurs for instance if a function which is supposed to be called with an integer argu-ment, is called with for example a Decimal No. argument.

2. The evaluation of the expression at the right-hand side of an assignment oper-ator (:=) results in a type which differs from the type of the variable at the left-hand side.

The automatic type conversion in assignments can take freely place between the following Number datatypes, provided overflow does not occur:

Numbers: Option ⇔ Integer ⇔ Long Integer ⇔ Decimal No.

The automatic type conversion in assignments can also take freely place between

Page 16: Guide to the Navision Al Dbms

12 AL Programmers Guide

Elements in AL Expressions

the String datatypes:

Strings: Code ⇔ Text

All the above has been based on simple variables. Nevertheless the same assignment rules apply for arrays in AL. Furthermore, if the left operand in an assignment (the variable) is an array, the dimension(s) of the right-hand side expression must correspond to the dimension(s) of the variable.

The following shows some examples of assignments:

Example

Let the variable A be defined as a one-dimensional array with 4 elements of the type Text with the maximum length 10. A value could be assigned to the second element in the array as shown below:

A[2]:= '0123456789';

Example

Let the variables Result, Amount and Total be defined as:

• Result has the type Option.

• Amount and Total both have the type Decimal No.

Consider the following assignment statements:

Amount := 10;

Total := 4;

Result := Amount + Total;

The above code can always be compiled, but a run-time error will occur if the result of the right-hand side expression 'Amount + Total' exceeds the valid range of the datatype of the left-hand side variable (outside the range of 0 to 255).

Valid Assignments

Table 8, “Valid assignments in AL,” on page 13 provides an overview of whether it is possible to assign the value of an expression of a given type to a variable of a given type. The rows describe the type of the variable, and the columns describe the type of the expression. The following signs are used in the table:

Note: The type conversion that takes place in assignments can cause run-time errors even though the types are convertable. A run-time error can occur in an assignment if the converted value is outside the valid range for the left hand side variable. Correspondingly a run time error can occur if the converted value is outside the valid range for a parameter in a function call.

Yes The assignment is valid.

(Yes) The assignment is valid, but overflow may occur.

- No, the assignment is invalid

Page 17: Guide to the Navision Al Dbms

AL Programmers Guide 13

Elements in AL Expressions

OperatorsOperators can be used in expressions in order to combine, investigate and manipulate values and data elements. In the following the function of the operators in AL are described.

Table 9 shows the valid operators in AL.

Table 8: Valid assignments in AL

Valid? YesNo Option IntegerLong Integer

Decimal No.

Date Time Text Code

YesNo Yes - - - - - - - -

Option - Yes (Yes) (Yes) (Yes) - - - -

Integer - Yes Yes (Yes) (Yes) - - - -

Long Integer - Yes Yes Yes (Yes) - - - -

Decimal No. - Yes Yes Yes Yes - - - -

Date - - - - - Yes - - -

Time - - - - - - Yes - -

Text - - - - - - - (Yes) (Yes)

Code - - - - - - - (Yes) (Yes)

Table 9: Operators in AL

AL Operator Meaning

. Fields in records

( ) Parentheses

[ ] Indexing

+ Addition

- Subtraction or negation

* Multiplication

/ Division

DIV Integer division

Variable Type

Expression Type

Page 18: Guide to the Navision Al Dbms

14 AL Programmers Guide

Elements in AL Expressions

The '+' and the '-' operators can be used both as unary and binary operators, the 'NOT' operator only as an unary operator, while all other operators are binary.

Most of the above operators can be used on different datatypes. The action of these operators may depend upon the datatype of expression they are used on. A typical example:

Example:

The '+' operator can be used as a binary operator in for example:

• Number + Number, which returns the sum of the numbers, that is a result of the type Number.

• String + String, which returns the concatenation of the strings, that is a result of the type String.

Furthermore the '+' operator can be used as an unary operator to indicate sign, for instance:

• + 34545

One of the following chapters “Type Conversion in Expressions” on page 23 will show how the function of the operators vary according to the data types of the applied arguments.

Operator HierarchyThe operators just discussed, are organized in a hierarchy which decides the order of evaluation of the operands in a given expression. The list below shows the precedence order of the AL operators:

1. .(fields in records), [] (indexing), () (parentheses)

2. NOT, - (unary), + (unary)

3. *, /, DIV, MOD, AND

4. +, -, OR

5. >, <, >=, <=, =, <>

Example

This example illustrates the effect of the operator hierarchy. The expressions

MOD Modulus

> Greater than

>= Greater than or equal to

< Less than

<= Less than or equal to

= Equal to

<> Not equal to

AND Logical Conjunction

OR Logical Disjunction

NOT Logical negation

Table 9: Operators in AL

Page 19: Guide to the Navision Al Dbms

AL Programmers Guide 15

Elements in AL Expressions

below, which apparently are the same, will produce different results.

The expression 2 + 3 * 4 is evaluated to 14, whereas

the expression (2 + 3) * 4 is evaluated to 20.

Function CallsAL covers a number of functions for different purposes, such as string handling, text formatting, database handling and so on. Some of these functions differ from standard Pascal, as it is possible to use a variable number of parameters. In a function call, the parameters are separated by commas, and the optional parameters may be omitted from the right.

This means that if the function has, for instance, 3 optional parameters, then it is not possible to omit the second without omitting the third:

Example

The fictitious function:

FUNCTION([Optional1] [, Optional2] [, Optional3])

can then be called, as:

FUNCTION(Optional1, Optional2)

but not as:

FUNCTION(, Optional2, Optional3)

Example

A typical example of a normal Pascal-like function is ABS.

Value := -1033; {A negative integer value}

PositiveValue := ABS(Value); {Calculate the positive value 1033}

ABS is a typical example of an AL function with a fixed number of parameters (1).

Example

The function DMY2DATE is a typical example of a function which can be called with a variable number of parameters:

NewDate := DMY2DATE(5, 11, 1992);{Returns the date November 5, 1992}

Depending on the use of the DMY2DATE function 1, 2 or 3 parameters can be passed to the function, as the second and third parameter are optional. When the second and third parameters are not used, the system uses values from the system date as default.

Page 20: Guide to the Navision Al Dbms

16 AL Programmers Guide

The AL Control Language

This section describes the basic constructs in the control language in AL and how to use them. All the AL programs you create consist of one or more statements. The statements are executed sequentially in top-down order. However, you will often need to control the direct top-down flow of the execution. You might desire, for one reason or another, to repeat the execution of one or more statements a number of times, or in other situations you might desire to make the execution of a certain statement conditional and so on.

Various control constructs are available in AL, just like in Pascal. These control constructs can be used to design very complex control structures, in order to take different actions according to the current state of the execution.

The control constructs in AL are divided into the following main groups:

• Compound Statements

• Conditional Statements

• Repetitive Statements

• WITH Statements

Compound StatementsIn some cases the AL syntax will only allow use of a single statement. If you desire to execute more than one simple statement in such a case, the statements can be turned into a compound statement, by 'encapsulating' the statements between the keywords BEGIN and END. The syntax is:

BEGIN

<Statement 1>;

<Statement 2>;

.

.

<Statement n>;

END

The individual statements are separated by a semicolon. In AL and Pascal a semicolon is used to separate statements, and not as in other programming languages as a terminator symbol for a statement. Nevertheless an extra semicolon before an END does not cause an error, because it is interpreted by the compiler as an empty statement.

The above BEGIN END structure is also called a block. Blocks can be very useful in connection with the other control constructs to be discussed in the following.

Conditional StatementsBy using a conditional statement, you can specify a condition and one or more commands to be executed according to if the condition is evaluated to TRUE or FALSE. There are two types of conditional statements in AL:

1. IF THEN [ELSE], when there are a maximum of 2 selections.

2. CASE, when there are multiple selections.

IF THEN ELSE

The ALControl

Language

Page 21: Guide to the Navision Al Dbms

AL Programmers Guide 17

The AL Control Language

This statement type has the following syntax:

IF <Condition> THEN <Statement1> [ ELSE <Statement2> ]

Which means:

If <Condition> is true, <Statement1> is executed. If <Condition> is false, <Statement2> is executed. As defined earlier, the square brackets around ELSE <Statement2> means that this part of the statement is optional.

This statement is used when different actions are to be executed, depending on the evaluation of the <Condition>

It is possible to build even more complex control structures by nesting IF THEN ELSE statements. A typical example is:

IF <Condition1> THEN IF <Condition2> THEN <Statement1> ELSE <Statement2>

If <Condition1> is false, nothing is executed. If <Condition1> and <Condition2> are both true, <Statement1> is executed. If <Condition1> is true, and <Condition2> is false, <Statement2> is executed. Please notice that a semicolon preceding an ELSE is not allowed.

Several nested IF THEN ELSE statements may seem confusing but a general rule is that an ELSE belongs to the last IF that lacks an ELSE.

Here are some examples of IF THEN ELSE statements:

Example

Illustration of an IF statement without the optional ELSE part:

IF Amount < 1000 THEN Total := Total + Amount;

Example

(1).

(2) IF Amount < 1000

(3) THEN BEGIN

(4) IF I > J THEN Max := I

(5) ELSE Max := J;

(6) Amount := Amount * Max;

(6) END

(7) ELSE

(8).

A common error for the AL novice, is to put an extraneous semicolon at the end of a line before an ELSE (line 4). As mentioned above this is not valid according to the syntax of AL, as the semicolon is used as a statement separator. (The end of line 4 is inside the inner IF statement).

CASE

The syntax for the CASE statement is:

CASE <Expression> OF

<Value set 1> : <Statement 1>;

Page 22: Guide to the Navision Al Dbms

18 AL Programmers Guide

The AL Control Language

<Value set 2> : <Statement 2>;

...

...

<Value set n> : <Statement n>;

[ELSE <Statement n+1>]

END;

In the above definition the <Expression> cannot be a record, and the <Value set> must be an expression.

CASE statements are also called multi-option statements and are typically used when a selection between more than two different actions are to be made. The function of the CASE statement is as follows:

The Expression is evaluated, and the first value set matching, causes an associated statement to be executed.

If none of the value sets matches the value of the expression and the ELSE part has been omitted, no action will be taken; but if the optional ELSE part is used, then the associated statement will be executed.

The type of the value sets must be the same as the type of <Expression> or at least convertable to the same type.

Example

This AL code sample will print various messages depending on the value of Number. If the value of Number does not match any of the entries in the CASE structure, the ELSE entry will be used as default.

CASE Number OF

1,2,9: MESSAGE('1, 2 or 9');

3,89,17: MESSAGE('3, 89 or 17');

ELSE MESSAGE('Neither 1, 2, 3, 9, 17 nor 89');

END

Repetitive StatementsA repetitive construct is also known as a loop. The looping constructs in AL are:

• FOR, which repeats the inner statements until a counter variable equals the maximum or minimum value specified.

• WHILE, which repeats the inner statements while the specified condition is TRUE. The statements in a loop of this type is repeated 0 or more times.

• REPEAT, which repeats the inner statements until the specified conditions evaluates to FALSE . The statements in a loop of this type is always executed at least one time.

FOR TO/DOWNTO

The syntax for the FOR TO (and FOR DOWNTO) statement is:

Note: The datatype of the value sets will be converted to the same datatype as the evaluated <expression>, if necessary. Due to this type conversion, an overflow may occur at run-time, if the resulting datatype cannot hold the values of the value sets.

Page 23: Guide to the Navision Al Dbms

AL Programmers Guide 19

The AL Control Language

FOR <Control Variable> := <Start Number> TO <End Number> DO <Statement>

<Control Variable>, <Start Number> and <End Number> must be Yes/No, Number, Time or Date datatypes.

FOR statements are used when a code block is to be executed a specific number of times. A control variable is used to control the number of times the code block is executed. The <Control Variable> may be increased or decreased by one, according to whether TO or DOWNTO is used.

When using a FOR TO loop, the <Statement> will not be executed if the <START NUMBER> is greater than the end value. Correspondingly, the <Statement> will not be executed in the FOR DOWNTO loop, if the start value is less than the end value.

Example

The following FOR loop uses a control variable Count of the type Integer.

FOR Count := 1000 TO 1000000 DO

When the above statement is executed, a run-time error will occur, because the system tries to convert the start and end values to the same type as the control variable; but as Count has been declared as an Integer variable, an error will occur when 1000000 is to be converted, because this end value is outside the valid range for Integers.

Example

This example illustrates nesting of FOR statements:

FOR I := 1 TO 5 DO

FOR J := 1 TO 7 DO

A[I,J] := 23;

The two FOR statements above could be used to initialize all elements in a 5 x 7 array with the value 23;

WHILE DO

The WHILE DO statement has the following syntax:

Note: If the user changes the value of the control variable inside the FOR loop, the behaviour of the system is not predictable. Furthermore the value of the control variable is undefined outside the scope of the FOR loop.

Note: When declaring the type of the <Control Variable> it should be noticed that when the system executes the FOR statement, the <Start Number > and <End Number> will be converted to the same datatype as <Control Variable>, if necessary. Due to this type conversion a run-time error may occur. This is illustrated in the following example:

Page 24: Guide to the Navision Al Dbms

20 AL Programmers Guide

The AL Control Language

WHILE <Condition> DO <Statement>

If <Condition> is true, <Statement> is executed repeatedly, until <Condition> becomes FALSE. If <Condition> is false from the start, <Statement> is never executed.

When a block of code is to be repeated as long as an expression is true, the WHILE DO statement may come in handy.

Example

The AL code below increases the variable i until it equals 1000:

WHILE i < 1000 DO i := i + 1;

REPEAT UNTIL

The syntax for the REPEAT UNTIL statement is:

REPEAT <Statement> UNTIL <Condition>

<Statement> will be executed repeatedly until <Condition> is TRUE.

This construct might at first glance seem to function just like the WHILE construct, but as the REPEAT UNTIL statement is executed from left to right, it is easily seen that the <Statement> always will be executed at least one time no matter what the <Condition> is evaluated to . This contrasts to the WHILE construct which performs the evaluation before the <Statement> is executed. This implies that if the first evaluation of <Condition> returns TRUE, then no statements will be executed.

Example

A typical use of the REPEAT UNTIL construct:

S:= ''; {The empty string}

REPEAT

S:= S + ' '; {Accumulate space characters in S}

UNTIL STRLEN(S) = 30;

The above AL code will store 30 spaces in the (Text) variable S.

EXIT StatementsThe EXIT statement is yet another construct you can use to control the flow of the execution. The syntax of an EXIT statement is:

EXIT([<Value>])

An EXIT statement is used to interrupt the execution of an AL trigger . The interruption will be effected even though the execution is inside a loop or a similar structure. The EXIT statement is also used when a local function is to return a value: EXIT(Value).

Using EXIT without a parameter in a local function, corresponds to using the parameter value 0, that is, the AL function will return the value 0 or '' (empty

Page 25: Guide to the Navision Al Dbms

AL Programmers Guide 21

The AL Control Language

string).

A compile-time error will occur if EXIT is called with a return parameter from:

1. System defined triggers

2. Local functions, which is not supposed to return a value

Example

The following illustates the use of the EXIT statement in an arbitrary local function. Assume that the IF statement is used to detect an error. If the error-condition is met, the execution is stopped and the local function returns the error-code 1.

FOR I := 1 TO 1000 DO

BEGIN

IF Amount[I] < Total[I] THEN EXIT(1);

A[I] := Amount[I] + Total[I];

END;

WITH StatementsThe syntax for the WITH statement is:

WITH <Record> DO <Statement>

When working with records, addressing is carried out as the record name, a dot and the field name: <Record>.<Field>

If you continuously work with the same record, then you can use WITH statements. When you use a WITH statement it will not be necessary to specify the record name more than once.

Within the scope of <Statement>, fields in <Record> may be addressed without specification of the record name.

Several nested WITH statements may be used. In case of identical names, the inner WITH will overrule the outer WITH-statements. The only restriction on the use of nested WITH statements, is that WITH cannot be used on an element in an array of records.

Example

This example shows two ways of writing the same code:

CustomerRec.No:= '1234';

CustomerRec.Company:= 'Windy City Solutions';

CustomerRec.Manager:= 'Joe Blow';

CustomerRec.Address:= '1241 East Druid Avenue';

CustomerRec."State and Zip":= 'Chicago, IL 60079';

another way of expressing the same, is:

WITH CustomerRec DO

BEGIN

No:= '1234';

Company:= 'Windy City Solutions';

Manager:= 'Joe Blow';

Address:= '1241 East Druid Avenue';

Page 26: Guide to the Navision Al Dbms

22 AL Programmers Guide

The AL Control Language

"State and Zip":= 'Chicago, IL 60079';

END;

Comments in ProgramsYou can insert comments about the code, or 'outcomment' parts of your code temporarily to prevent its execution.

A comment starts with '{' or ‘’and ends with '}' or ''. Any number of nested comments may occur. In such cases, the comment runs from the first comment start to the last comment end.

The system does not distinguish between the '{ '- and ''- type comments, that is, it is possible to start a comment using a '{' and end it with a ''. The user should be aware of this when using lines to draw figures inside a comment.

Example:{

This is a sample comment which is ignored by the AL compiler

}

Example:

{ This comment { is partly inside } another comment }

Example:

The last example illustrates how you should not do when you a apply a box comment:

By placing the box comment to the right of the AL statements, the third and fourth lines are assumed by the system to be part of the comment, that is, only A and B are assigned values, while C and D are not. The solution is to separate the box comment from the AL statements, like:

A := 34;

B := 56;

C := 345;

D := 781;This is a box comment

A := 34;

B := 56;

C := 345;

D := 781;

This is a box comment

Page 27: Guide to the Navision Al Dbms

AL Programmers Guide 23

Type Conversion in Expressions

Consider the following statement:

Sum := 1556 + 56000;

A statement of this type involves one or two type conversions. The right-hand side of the statement involves the evaluation of the expression 1556 + 56000 (in other words Integer + Long Integer). In order to evaluate this expression, the first operand (1556) will have to be converted from Integer to Long Integer. The addition operator will then return a Long Integer result. But if the type of the left-hand side variable has been declared as for instance Decimal No., a type conversion from Long Integer to Decimal No. has to take place before the value can be assigned to Sum. The latter category of conversion has already been discussed. See “Assignment and Type Conversion” on page 11.

In this section we will consider the type conversion that (might) take place when expressions are evaluated.

Initially some general rules can be outlined:

• When asked to evaluate an expression of mixed datatypes, the system will (if possible) always convert, a least one of the operands to a more general datatype.

• The datatypes in the two main groups Numbers and Strings, can be ranked from 'most general' to 'least general', as defined below.

• The most general datatypes include all possible values from the less general datatypes. The above should be interpreted as follows: a Decimal No. is more general than a Long Integer, which again is more general than an Integer and so on.

• Type conversion can take place in some cases although two operands have the same type. A typical example is an expression like:

Integer + Integer

In this case the system will convert both the operands to Long Integers, and the resulting datatype will be Long Integer.

The above rules can be illustrated by some examples.

Example:

Evaluation of a Number expression:

Integer + Decimal No.

This expression contains two sub-expressions of different type. In order to add these, the system will convert the left sub-expression to Decimal No.:

Numbers Strings

Most General Decimal NoText

Long Integer

Least General

IntegerCode

Option

Type Conversionin Expressions

Page 28: Guide to the Navision Al Dbms

24 AL Programmers Guide

Type Conversion in Expressions

Decimal No.+ Decimal No

When the left-hand side sub-expression has been converted, the expression can be evaluated, and the resulting data type will be Decimal No.:

Decimal No. + Decimal No. ⇒ Decimal No.

Example:

Evaluation of a String expression:

Text + Code

This expression contains two sub-expression to be concatenated. In order to do this, the system will convert the sub-expression of the least general data type (Code) to the most general data type (Text).

Text + Text

When the right-hand side argument has been converted, the expression can be evaluated, and the resulting datatype will be Text.

Text + Text ⇒ Text.

Type Conversion MechanismsWe will now turn to a detailed discussion of the type conversion mechanisms for the operators in AL. We start by dividing the operators into some main categories:

• Relational operators

• Logical operators

• Arithmetic operators

The following sections aim at discussing the properties of the operators in AL. For each category of operators the valid datatypes for the arguments are discussed, and furthermore we define the resulting data types when evaluating expressions.

We will start with a discussion of the so-called relational operators, as these are common to most of the AL datatypes.

Relational OperatorsThe relational operators are used to compare expressions. Table 10 defines the evaluation rules for relational operators. The rules assume that the expressions evaluates to comparable types. Please refer to Table 11, “Valid uses of relational operators,” on page 26 for an overview of which datatypes are comparable.

Page 29: Guide to the Navision Al Dbms

AL Programmers Guide 25

Type Conversion in Expressions

Table 11, “Valid uses of relational operators,” on page 26 describes the valid uses of the relational operators, and the resulting datatype when an expression containing relational operators has been evaluated. The invalid combinations of types for relational operators are indicated by a dash.

Table 11 should be interpreted as follows1: the rows show the type of the left argument and the columns show the type of the right argument, in other words:

ResType = LeftArgument RelationalOperator RightArgument

From the table you can see that a valid use of the relational operators is, for example Text compared with Text or Code, while Yes/No cannot be compared with anything else than Yes/No and so on.

1. All relational operators are binary infix operators, in other words, takes a left and a right argument and are placed between the arguments.

Table 10: Relational operators

Operator Name ExpressionResulting Datatype

> Greater than Expr > Expr Yes/No

< Less than Expr < Expr Yes/No

<= Less than or equal Expr >= Expr Yes/No

<> Not equal to Expr <> Expr Yes/No

= Equal to Expr = Expr Yes/No

Note: When using relational operators the following should be observed: Upper and lower case letters in Strings are taken to be different. The comparison is carried out by means of the system's build in character comparison table, that is, not by comparing true ASCII characters

Page 30: Guide to the Navision Al Dbms

26 AL Programmers Guide

Type Conversion in Expressions

Table 11: Valid uses of relational operators

Relational Operators

Yes/No Option IntegerLong Integer

Deci-mal No.

Date Time Text Code

Yes/No Yes/No - - - - - - - -

Option - Yes/No Yes/No Yes/No Yes/No - - - -

Integer - Yes/No Yes/No Yes/No Yes/No - - - -

Long Integer - Yes/No Yes/No Yes/No Yes/No - - - -

Decimal No. - Yes/No Yes/No Yes/No Yes/No - - - -

Date - - - - - Yes/No - - -

Time - - - - - - Yes/No - -

Text - - - - - - - Yes/No Yes/No

Code - - - - - - - Yes/No Yes/No

Right Argument

Left Argument

Page 31: Guide to the Navision Al Dbms

AL Programmers Guide 27

Type Conversion in Expressions

Yes/No (Logical) OperatorsThe logical operators can only be used with arguments which evaluates to the type Yes/No.

As table 12 shows, the NOT operator is a unary prefix operator, that is, takes only one argument and is placed in front of the argument, while the AND and OR operators are binary infix operators, that is takes two arguments and are placed between the corresponding arguments.

Introduction to Arithmetic OperatorsIn order to introduce the arithmetic operators, we start this section by showing some examples, which exemplifies the function of the operators, and illustrate the implicit type conversion automatically made by the AL compiler. The examples has been divided into groups corresponding to each of the datatypes in AL.

It is important to stress that the examples by no means are exhaustive. For a full description of the type conversion rules in AL please refer to the tables in the sections “The Unary Arithmetic Operators” and “The Binary Arithmetic Operators” on page 31. These provide a full description of all possible uses of AL operators and the resulting datatypes.

Examples: Option Operators

Table 12: Yes/No operators

Operator: Name: Expression:Resulting Datatype:

NOT Logical negation NOT Yes/No Yes /No

AND Logical andYes/No AND Yes/No

Yes/No

OR Logical or Yes/No OR Yes/No Yes/No

Table 13: Option operators

Operator: Name: Expression:Resulting Datatype

+ Addition Option + Integer Integer

+ Addition Integer + Option Integer

- Subtraction Option - Integer Integer

- Subtraction Integer - Option Integer

Page 32: Guide to the Navision Al Dbms

28 AL Programmers Guide

Type Conversion in Expressions

Examples: Integer Operators

Examples: Long Integer Operators

Examples: Decimal No. Operators

Table 14: Integer operator examples

Operator: Name: Expression:Resulting Datatype

+ Unary plus + Integer Integer

- Unary minus - Integer Integer

+ Addition Integer + Integer Long Integer

- Subtraction Integer - Integer Long Integer

* Multiplication Integer * Integer Long Integer

/ Division Integer / Integer Decimal No.

DIV Integer division Integer DIV Integer Integer

MOD Modulus Integer MOD Integer Integer

Table 15: Long Integer operator examples

Operator: Name: Expression:Resulting Datatype

+ Unary plus + Long Integer Long Integer

- Unary minus -Long Integer Long Integer

+ Addition Long Integer + Long Integer Long Integer

- Subtraction Long Integer - Long Integer Long Integer

* Multiplication Long Integer * Long Integer Long Integer

/ Division Long Integer / Long Integer Decimal No.

DIVInteger divi-sion

Long Integer DIV Long Integer Long Integer

MOD Modulus Long Integer MOD Long Integer Long Integer

Page 33: Guide to the Navision Al Dbms

AL Programmers Guide 29

Type Conversion in Expressions

Examples: Date Operators

In the 'Date addition' and 'Date subtraction' examples above, a run-time error will occur if Date is a closing date. If date is undefined (0D), a run-time error will occur.

Examples: Time Operators

Table 16: Decimal No. operator examples

Operator: Name: Expression:Resulting Datatype

+ Unary plus + Decimal No. Decimal No.

- Unary minus - Decimal No. Decimal No.

+ Addition Decimal No. + Decimal No. Decimal No.

- Subtraction Decimal No. - Decimal No. Decimal No.

* Multiplication Decimal No. * Decimal No. Decimal No.

/ Division Decimal No. / Decimal No. Decimal No.

DIV Integer Division Decimal No. DIV Decimal No. Decimal No.

MOD Modulus Decimal No. MOD Decimal No. Decimal No.

Table 17: Date operator examples

Operator: Name Expression:Resulting Datatype

+ Date addition Date + Number Date

- Date subtraction Date - Number Date

- Date difference Date - Date Integer

Table 18: Time operator examples

Operator: Name: Expression:Resulting Datatype

+ Time addition Time + Integer Time

+ Time addition Time + Long Integer Time

Page 34: Guide to the Navision Al Dbms

30 AL Programmers Guide

Type Conversion in Expressions

The time unit is milliseconds. If time is undefined (0T), a run-time error will occur.

Examples: Text and Code (String) Operators

This ends the examples of the arithmetic operators. At this point you should feel quite comfortable with the basic uses of the arithmetic operators in AL. Nevertheless the above examples do not cover all the possible uses of the operators. The following tables provide a full description of uses of the arithmetic operators and the resulting datatypes.

The Unary Arithmetic Operators

The unary arithmetic operators in AL are so-called prefix operator, in other words the syntax is:

PrefixExpression = Prefix Operator Expression

Table 20 shows for which datatypes the unary operators in AL are defined, and the resulting datatypes returned by the system.

Invalid uses of the unary operators are indicated in the table by a dash. The table shows that for instance the expression '- Integer' is valid, and evaluates to Integer, while an expression like '+Yes/No' is invalid.

- Time subtraction Time - Long Integer Time

- Time difference Time - Time Long Integer

Table 19: Text and Code operator examples

Operator: Name: Expression:Resulting Datatype

+ Concatenation Text + Text Text

+ Concatenation Text + Code Text

+ Concatenation Code + Text Text

+ Concatenation Code + Code Code

Table 20: Validity of unary operators

Unary Oper-ator

Integer Long Integer Decimal No.

Table 18: Time operator examples

Operator: Name: Expression:Resulting Datatype

Page 35: Guide to the Navision Al Dbms

AL Programmers Guide 31

Type Conversion in Expressions

The Binary Arithmetic Operators

The binary arithmetic operators in AL are so-called infix operators, that is of the following type:

InfixExpression = LeftExpression InfixOperator RightExpression

Table 21 shows for which datatypes the binary arithmetic operators are defined. In the table the following signs are used:

Each of the following tables define the valid uses of the binary arithmetic operators, and the resulting datatypes.

+ Integer Long Integer Decimal No.

- Integer Long Integer Decimal No.

YesYes, the operator can take at least one operand (left, right or both) of the given type.

- No, the operator cannot be used with the given type.

Table 21: Binary arithmetic operators

Defined? Yes/No Option IntegerLong Integer

Decimal No.

Date Time Text Code

+ - Yes Yes Yes Yes Yes Yes Yes Yes

- - Yes Yes Yes Yes Yes Yes - -

* - - Yes Yes Yes - - - -

/ - - Yes Yes Yes - - - -

DIV - - Yes Yes Yes - - - -

MOD - - Yes Yes Yes - - - -

Table 20: Validity of unary operators

Page 36: Guide to the Navision Al Dbms

32 AL Programmers Guide

Type Conversion in Expressions

The '+' Operator

(A) in the above table means that the operation is not defined for the date 0D.

(B) in the above table means that the operation is not defined for the time 0T.

(C) in the above table indicates that overflow may occur.

(D) in the above table indicates that the operation is not defined if Decimal No. has a fractional part.

Table 22: Resulting data type from the ‘+’ operator

+Yes/No

Option IntegerLong Integer

Decimal No.

Date Time Text Code

Yes/No - - - - - - - - -

Option - -Long Integer

Long Inte-ger(C)

Decimal No. (C) - - - -

Integer -Long Integer

Long Integer

Long Inte-ger(C)

Decimal No. (C) - - - -

Long Inte-ger

-Long Inte-ger(C)

Long Integer (C)

Long Inte-ger(C)

Decimal No. (C) - - - -

Decimal No.

-Decimal No.(C)

Deci-mal No. (C)

Deci-mal No. (C)

Decimal No. (C) - - - -

Date - -Date(A) (C)

Date(A)

(C)Date(A) (C) (D) - - - -

Time - -Time(B) (C)

Time(B)

(C)Time(B) (C) (D) - - - -

Text - - - - - - - Text Text

Code - - - - - - - Text Code

Right Argument

Left Argument

Page 37: Guide to the Navision Al Dbms

AL Programmers Guide 33

Type Conversion in Expressions

The '-' Operator

(A) in the above table means that the operation is not defined for the date 0D.

(B) in the above table means that the operation is not defined for the time 0T.

(C) in the above table means that overflow may occur.

(D) in the above table indicates that the operation is not defined if Decimal No. has a fractional part.

Table 23: Resulting data type from the ’-’ operator

- Yes/No Option IntegerLong Integer

Decimal No.

Date Time Text Code

Yes/No - - - - - - - - -

Option - -Long Integer

Long Integer (C)

Decimal No. (C) - - - -

Integer -Long Inte-ger

Long Integer

Long Integer (C)

Decimal No. (C) - - - -

Long Integer

-Long Inte-ger (C)

Long Integer (C)

Deci-mal No. (C)

Decimal No. (C) - - - -

Deci-mal No.

-Decimal No. (C)

Deci-mal No. (C)

Deci-mal No. (C)

Decimal No. (C) - - - -

Date - -Date(A) (C)

Date(A) (C)

Date(A) (C) (D)

Inte-ger(A) (C)

- - -

Time - -Time(B) (C)

Time(B) (C)

Time(B) (C) (D) -

Long Inte-ger(B)

- -

Text - - - - - - - - -

Code - - - - - - - - -

LeftArgument

Right Argument

Page 38: Guide to the Navision Al Dbms

34 AL Programmers Guide

Type Conversion in Expressions

The ‘*’ Operator

.

The ‘/’ Operator

A run-time error will occur if the right operand is equal to zero (0).

Table 24: Resulting data type from the ‘*’ operator

* IntegerLong Inte-ger

Decimal No.

IntegerLong Integer (C)

Long Integer (C)

Decimal No. (C)

Long Integer

Long Integer (C)

Long Integer (C)

Decimal No. (C)

Decimal No.

Decimal No. (C)

Decimal No. (C)

Decimal No. (C)

Table 25: Resulting data type from the ‘/ ‘ operator

/ IntegerLong Integer

Decimal No.

IntegerDecimal No.

Decimal No.

Decimal No.

Long Inte-ger

Decimal No.

Decimal No.

Decimal No.

Decimal No.

Decimal No.

Decimal No.

Decimal No.

Right Argument

LeftArgument

Right Argument

LeftArgument

Page 39: Guide to the Navision Al Dbms

AL Programmers Guide 35

Type Conversion in Expressions

The 'MOD' and 'DIV' Operators

A run-time error will occur if the right operand is equal to zero (0).

Table 26: Resulting data type from the ‘MOD’ and ‘DIV’ operators

MOD and DIV Integer Long Integer Decimal No.

Integer Integer Long Integer Decimal No.

Long Integer Long Integer Long Integer Decimal No.

Decimal No. Decimal No. Decimal No. Decimal No.

Right Argument

Left Argument

Page 40: Guide to the Navision Al Dbms

36 AL Programmers Guide

Type Conversion in Expressions

Page 41: Guide to the Navision Al Dbms

AL Reference Guide2Part

AL Reference Guide 37

This document provides a detailed overview of the functions in the Appli-cation Language (AL). The functions are ordered alphabetically and the aim is that this document should serve as a reference for AL program-mers.

For each AL function, the functioning, the syntax and the arguments are explained. Furthermore there will often be general comments on the use of the function, and all entries will be illustrated by AL code examples. The figure below explains the layout used in the rest of this document.

Use this function to load and run a batch job. For example, you can use this function to call a batch job that adjusts inventory

callBATCH(BatchName [, Request])

- Flow: i; data types: String

Enter the name of the batch you want to run. To choose from the list of batch jobs, press F5 while in the AL editor. The system displays the Symbols list. Highlight CallBatch and press F6

-Flow: i; data types: Yes/No

Use this parameter to determine whether or not the request panel appears before the system runs the batch job. The request panel lets the user select the set of information to include and other options.

If you display the request panel, please note that the user has to press ESC after the batch job runs to exit the request panel and start the next AL function.

These examples show how to call a batch job. The first example shows the request panel. The second example skips the request panel and starts the batch job immediately.

With a request panel

Name := �Adjust Item Prices�; Sets the name of the

batch

callBATCH(Name); Displays the request panel and

then, after the user selects

Start, runs the batch job

Without a request panel

Name := �Adjust Item Prices�; Sets the name of the

batch

callBATCH(Name, FALSE); Runs the batch job

To... Enter...

Display the request panel before the batch job starts

TRUE or leave blank (default)

Start the batch job without displaying the request panel

FALSE

Note : If the batch job does not exist, the system displays a

message when it executes this function

callBATCH

BatchName

Request

For Example ...

A description of the argu-ment(s) used in the function. For each argument the Flow is described. The Flow can be either in (i), out (o) or io (in/out), describing whether the argument is used as input, output or both. Fur-thermore the valid data types are defined

The heading to the left describes the name of the function

This table tells you how to accomplish some common tasks

A thick vertical bar will be used to draw your attention to notes on special cases and potential errors that you should be aware of.

All AL functions are exem-plified by code samples

Page 42: Guide to the Navision Al Dbms

Typographical Conventions

38 ALReference Guide

This document uses special typefaces to help you distinguish between various types of text.

Table 27 illustrates these conventions:

Table 27: Conventions

Convention Applies to Examples

Monospaced Font AL code examples Number:= 6;

Times Font Normal text This is a sentence

Helvetica Font Table bodies Text in a table cell

ALL CAPSAL keywords when used in normal text and in AL code examples

...by using the MES-SAGE function...

TypographicalConventions

Page 43: Guide to the Navision Al Dbms

AL Functions grouped by category

AL Reference Guide 39

This section presents the AL functions grouped by category. The functions are divided into the following 9 main categories:

1. String functions

2. Date and Time functions

3. Number functions

4. Database functions

5. Dialogue functions

6. Accounting functions

7. Array functions

8. Miscellaneous functions

9. Call functions

Some of the above groups are divided further into sub-groups. The functions are described in alphabetical order from page 44.

String Functions

Maintenance

INSSTR Inserts a string into another string.

DELSTR Deletes a substring in a string.

DELCHR Deletes one or more characters in a string.

COPYSTR Copies (a part of) a string.

SETSTRLEN Adjusts the length of a string.

STRSUBSTNO Formats values into a string.

INCSTR Increases or decreases a number in a string with 1 (one).

SELECTSTR Selects a sub-string in a comma saparated string.

Information

STRLEN Returns the length of a string.

MAXSTRLEN Returns the maximum (defined) length for a string variable.

STRPOS Returns the position for a sub-string in a string.

Transformation

UPPERCASE Converts a string to uppercase.

LOWERCASE Converts a string to lowercase.

AL Functionsgrouped by

category

Page 44: Guide to the Navision Al Dbms

AL Functions grouped by category

40 ALReference Guide

CONVERTSTR Converts the characters in a string.

STRCHECKSUM Calculates a checksum for a numeric string.

Date and Time Functions

TIME Returns the current system time.

TODAY Returns the date from the operating system.

WORKDATE The NAVISION work date.

Transformation

NORMALDATE Returns the normal date for a date.

CLOSINGDATE Returns the closing date for a date.

CALCDATE Evaluates a date-expression.

DATE2DMY Returns day, month or year for a date.

DATE2DWY Returns weekday, weekno. or year for a date.

DMY2DATE Returns the date based on day, month and year.

DWY2DATE Returns the date based on weekday, week and year.

Number Functions

ABS Calculates the absolute value for a number.

ROUND Rounds off a number.

POWER Calculates xy

Database Functions

Maintenance

dbINSREC Inserts a record.

dbDELREC Deletes a record.

dbDELALL Deletes all records within a specified range.

dbMODIFYREC Edits a record.

dbMODIFYALL Edits a field in all records.

dbRECMARK Marks a record.

Searching

Page 45: Guide to the Navision Al Dbms

AL Functions grouped by category

AL Reference Guide 41

dbGETREC Finds a record based on the current key and filters.

dbFINDREC Finds a record based on the current key and filters.

dbNEXTREC Find the next or previous record, based on the specified record.

dbSETCURREC Marks a record as current record.

dbGETCURREC Retrieves a record, marked as current, from the Object Stack.

dbRECCOUNT The number of records in a table within a specified range.

Transactions

dbLOCKTABLE Locks a table in order to prevent conflicting write transactions

dbCONSISTENT Specifies whether a table is consistent.

dbCOMMIT Commits (approves) a write transaction.

Keys and filters

dbSELECTKEY Selects a current key for a table.

dbSETRANGE Assigns a simple filter (single range) to a field.

dbSETFILTER Assigns a filter to a field.

dbMINRANGE Finds the minimum value for a range.

dbMAXRANGE Finds the maximum value for a range.

dbCOPYFILTER Copies a filter from one field to another.

dbCOPYALLFILTERS Copies all filters and marks from one record to another record.

dbGETFILTER Returns the filter for a field.

dbGETALLFILTERS Returns all filters for a record.

dbMARKEDONLY Delimits to records which have been marked.

dbRESETTABLE Removes all filters for a table and selects the primary key.

dbGLOBALFILTER Makes all filters assigned to a table global.

dbSELECTCOMPANY Redirects references to table data to another company.

Fields

dbFIELDNO Returns the field number for a field.

Page 46: Guide to the Navision Al Dbms

AL Functions grouped by category

42 ALReference Guide

dbFIELDNAME Returns the field name for a field.

dbFIELDACTIVE Indicates if a field is active.

dbCALLFIELDCODE Calls Entry Processing code for a field.

dbFIELDERROR Creates an error message concerning a field.

dbTESTFIELD Tests the contents of a field.

dbTRANSFERFIELDS Copies fields from one record to another.

dbSUM Sums specified columns in a table.

dbCALCFIELDS Calculates the contents in calculated fields.

dbINITREC Initializes the fields in a record.

Dialogue Functions

OPENWINDOW Opens a window.

CLOSEWINDOW Closes a window.

UPDATEWINDOW Updates a field in a window with a value.

WINDOWINPUT Allows keying in a field in a window.

ERROR Prints a message and ends the AL code.

MESSAGE Prints a message when the execution of the AL code stops to wait for user interaction or is ended.

CONFIRM Creates a dialog box and prompts for a Yes/No answer.

STRMENU Creates a menu and waits for a selection.

WAITKEYPRESS Waits for a key to be pressed.

Accounting Functions

COMPANYNAME Returns the current Company name.

USERID Returns the current user ID.

Array Functions

COPYARRAY Copies a part of a one-dimensional array.

ARRAYLEN Returns the total number of elements in an array, or the number of elements in a specific dimension.

COMPRESSARRAY Removes empty strings in a text-array.

Page 47: Guide to the Navision Al Dbms

AL Functions grouped by category

AL Reference Guide 43

Miscellaneous Functions

EVALUATE Evaluates a text into a value.

FORMAT Formats a value to a string.

CLEAR Clears an internal variable.

CLEARALL Clears all internal variables, keys and filters.

SERIALNO Returns the serial number for your license file.

SYSTEMVERSION Returns the name and version of the operating system.

Call Functions

callWINDOW Loads and executes a window object.

callFUNCTION Loads and executes a function object.

callMENU Loads and executes a menu object.

callREPORT Loads and executes a report object.

callBATCH Loads and executes a batch object.

callIMPORT Loads and executes an import object.

callSYSTEM Executes a command in the operating system.

Page 48: Guide to the Navision Al Dbms

ABS

44 ALReference Guide

Calculates the absolute value of a Number, that is, ABS always returns a positive numeric value or zero.

NewNumber := ABS(Number)

- Flow: i; Data types: Number

The input value.

- Flow: o; Data types: Decimal No.

NewNumber ≥ 0.

This example shows how to remove the sign from a negative numeric value.

x := -10.235; {x is assigned a negative value}

y := ABS(x); {y is assigned the value of x without sign}

MESSAGE('x = %1, y = %2', x, y);

The message box will show:

x = -10.235, y = 10.235

Number

NewNumber

For Example...

ABS

Page 49: Guide to the Navision Al Dbms

ARRAYLEN

AL Reference Guide 45

Returns the total number of elements in an Array, or the number of ele-ments in a specific Dimension.

Length := ARRAYLEN(Array [, Dimension])

-Flow: i; Data types: Array

The array to be investigated.

-Flow: i; Data types: Number

If this optional argument is not used, the function will return the total number of elements in the Array. In order to get the number of elements in a specific dimension use Dimension with a valid value.

The valid values for Dimension are determined by the number of dimen-sions of the input array, for example the valid values for a three- dimen-sional array would be 1, 2 and 3.

-Flow: o; Data types: Integer

The number of elements in the array, or the number of elements in a spe-cific dimension.

The following AL code sample shows how to use the optional arguments.

{Array1 is a one-dimensional integer array with size 2}

{Array2 is a two-dimensional integer array with size 2x2}

MESSAGE('Array1, Total number of elements %1', ARRAYLEN(Array1));

MESSAGE('Array2, Dimension no. 1: Size %1', ARRAYLEN(Array2,1));

MESSAGE('Array2, Dimension no. 2: Size %1', ARRAYLEN(Array2,2));

MESSAGE('Array2, Total number of elements: %1', ARRAYLEN(Array2));

The message boxes will show:

Note : A run time error will occur if ARRAYLEN is used with an input parameter which is not an array.

Array1, Total number of elements: 2

Array2, Dimension no. 1: Size 2

Array2, Dimension no. 2: Size 2

Array2, Total number of elements: 4

ARRAYLEN

Array

Dimension

Length

For Example...

Page 50: Guide to the Navision Al Dbms

CALCDATE

46 ALReference Guide

Calculates a new date based on a DateExpression and a reference Date.

NewDate := CALCDATE(DateExpression [, Date])

-Flow: i; Data types: String

The date expression can be of any length. The system interprets the string from left to right, one sub-expression at the time. The following rules describes the valid syntax for a date expression:

DateExpression = <SubExpression>*

<SubExpression> = [<Sign>] <Term>

<Term> = <Number><Unit> | <Unit><Number>| <Prefix><Unit>

<Sign> = + | -

<Number> = Positive integer

<Unit> = D | WD | W | M | Q | Y

(D=day, WD=Weekday, W=Week, M=Month, Q=Quarter, Y=Year)

<Prefix> = C(C=Current)

The above (production-) rules express that date expressions consist of zero or more sub-expressions. Each sub-expression is made of one of three possible terms. Typical examples of terms are:

• 30D (30 days) corresponds to <Number><Unit>.

• WD2 (weekday no. 2) corresponds to <Unit><Number>

• CW (current week) corresponds to <Prefix><Unit>

- Flow: i; Data types: Date

This optional parameter can be used to define a reference date. The default value is the current system date.

- Flow: o; Data types: Date

The resulting date computed from the reference date and the date expres-sion.

The first example shows how to use the production rules above.

Prefix Unit Sign Number Unit Sign Number Unit

C Q + 1 M - 10 D

This should be interpreted as: Current quarter + 1 month - 10 days.

The second example shows how to use the CALCDATE function.

Expr1 := 'CQ+1M-10D'; {Current quater + 1 month - 10 days}

Note : The internal calendar used in AL starts on a Monday and ends on a Sunday. This means that Monday is weekday no. 1 and Sunday is weekday no. 7.

Note : If the syntax of DateExpression is wrong, a run time error will occur.

CALCDATE

DateExpression

Date

NewDate

For Example...

Page 51: Guide to the Navision Al Dbms

CALCDATE

AL Reference Guide 47

Expr2 := '-WD2'; {The previous Weekday no. 2, (last Tuesday)}

Expr3 := 'CM+30D'; {Current month + 30 days}

RefDate := 052196D;

Date1 := CALCDATE(Expr1, RefDate);

Date2 := CALCDATE(Expr2, RefDate);

Date3 := CALCDATE(Expr3, RefDate);

MESSAGE('The reference date is: %1 \' +

'The expression: %2 returns %3\' +

'The expression: %4 returns %5\' +

'The expression: %6 returns %7', RefDate, Expr1, Date1,

Expr2, Date2, Expr3, Date3);

The message box will show:

The reference date is: 05/21/96

The expression: CQ+1M-10D returns 07/20/96

The expression: -WD2 returns 05/14/96

The expression: CM+30D returns 06/30/96

Page 52: Guide to the Navision Al Dbms

callBATCH

48 ALReference Guide

Loads and executes a batch object identified by a BatchName.

callBATCH(BatchName [, Request])

- Flow: i; Data types: String

The name of the desired batch object. The string must contain an exact match of the name of the report object (case sensitive). To choose from the list of batch objects, press F5 while in the AL editor. The system dis-plays the Symbols survey. Highlight the callBATCH keyword and press F6.

- Flow: i; Data types: Yes/No

Determines whether the request window will be shown before the batch object is executed.

These examples show how to call a batch job. The first example shows the request window. The second example skips the request window and starts the batch job immediately.

With a request panel

Name := �Adjust Item Prices�; {Sets the name of the batch}

callBATCH(Name); {Displays the request window

and then, after the user

selects Start, runs the batch

job}

Without a request panel

Name := �Adjust Item Prices�; {Sets the name of the batch}

callBATCH(Name, FALSE); {Runs the batch job without

showing the request window}

Note : If the batch object BatchName does not exist, a run time error will occur.

To... Enter...

Display the request window before the batch is started

TRUE or leave blank (default)

Start the batch job without display the request window

FALSE

callBATCH

BatchName

Request

For Example...

Page 53: Guide to the Navision Al Dbms

callFUNCTION

AL Reference Guide 49

Loads and executes a function object identified by a FunctionNo.

[Ok :=] callFUNCTION(FunctionNo [, Record])

- Flow: i; Data types: Number

A number which identifies the desired function object. To choose from the list of function objects, press F5 while in the AL editor. The system displays the Symbols survey. Highlight the callFUNCTION keyword and press F6.

- Flow: i; Data types: Record

Denotes a record to be used by the function identified by FunctionNo.

There are two types of function objects in the AL system.The first type is associated to a specific table when it is created. When calling function objects of this type, only records corresponding to the type of the associ-ated table can be used. The second type of function object is not associ-ated to a table, and when calling functions of this type, the optional Record parameter cannot be used.

- Flow: o; Data types: Yes/No

If the optional return value is not used, the system will terminate the exe-cution of the AL code calling the function if an error occurs during the execution of the function object.

If the return value is used, the system will continue the execution of the calling AL code, although the function object detected an error, in other words the programmer is supposed to take care of the error handling. The possible values are described in the table below.

If the return value is used, the system will automatically clear the vari-ables used in the function object, before the function object is executed.

If you use the return value in an IF statement, inside a write transaction, a run time error will occur, unless your data updates are committed, before you call callFUNCTION.

Note : If the function object identified by FunctionNo does not exist, a run time error will occur.

Note : If a function has been associated to a specific table, a run time error will occur if the function is called with a record from a different table.

OK Means that...

TRUE No errors occured.

FALSEAn error occured during the execution of the function object.

callFUNCTION

FunctionNo

Record

Ok

Page 54: Guide to the Navision Al Dbms

callFUNCTION

50 ALReference Guide

When dbCOMMIT is used, all AL variables in Function objects currently loaded, will be cleared. Consider the following example:

When dbCOMMIT is executed, the AL variables used in the Function objects 1002 and 1003 will be cleared by the system. The AL variables in the Function object 1005 is not cleared, as the Function object has not been loaded into memory at the point in time dbCOMMIT is executed.

The following example shows how to use the callFUNCTION function.

Example 1:

A simple example, which shows how to call function no. 1001.

FunctionNo := 1001;

callFUNCTION(FunctionNo);

Example 2:

The Al code in this example uses a function numbered 1002, which calcu-lates a unit price.

Consider the following AL code sample:

IF callFUNCTION(1002,InvLine) THEN

MESSAGE(�Unit Price is now calculated�)

ELSE

ERROR(�Quantity was zero�);

By using the return value from callFUNCTION the programmer takes care of the error handling. The following two code samples would cause a run time error as the optional return value is not used:

callFUNCTION(1002,InvLine);

Stops code execution if Quantity = 0.

callFUNCTION(1002);

Works on local variable, will always stop code execution.

Example 3:

General Comments...

...

callFUNCTION(1002);

callFUNCTION(1003);

dbCOMMIT();

callFUNCTION(1005);

...

AL code module

For Example...

Function 1002 (Invoice Line)

�Unit Price� := Amount / Quantity;

Page 55: Guide to the Navision Al Dbms

callFUNCTION

AL Reference Guide 51

The AL code in this example uses a function numbered 1003, which increases a counter variable.

Consider the following AL code sample:

FOR i := 1 TO 100 DO

callFUNCTION(1003);

If we assume that the value of count initially is zero, this loop will cause count to be increased to 100. If the return value is used in a IF construct, like:

FOR i := 1 TO 100 DO

IF callFUNCTION(1003) THEN

MESSAGE(�Function 1003 called %1 times�,i);

then Count will be cleared each time function 1003 is activated. This will cause Count to take the values: 0->1, 0->1, 0->1 ...

Example 4:

The AL code in this example uses a function numbered 1004, which selects a key, and assigns a filter to the Customer table.

Consider the following AL code sample:

dbSELECTKEY(Customer.Name);

dbSETFILTER(Customer.�No.�, �>=2000�);

callFUNCTION(1004,Customer);

The call to the function 1004, does not change current key and filters. The changes made in the function are local to the function.

Example 5:

Consider the following write transaction:

...

dbINSREC(Customer);

IF callFUNCTION(1005) THEN

...

The above call to function 1005 results in a run time error, as the write transaction has not been committed. In order to call the function, the data update must be explicitly committed:

...

dbINSREC(Customer);

dbCOMMIT();

IF callFUNCTION(1005) THEN

...

Function 1003

Count := Count + 1;

Function 1004 (Customer)

dbSELECTKEY(Customer.�No.�);

dbSETFILTER(Customer.�No.�, �<1000�);

Page 56: Guide to the Navision Al Dbms

callIMPORT

52 ALReference Guide

Loads and executes an import object identified by an ImportName.

callIMPORT(ImportName [, Request])

- Flow: i; Data types: String

The name of the desired import object. The string must contain an exact match of the name of the report object (case sensitive). To choose from the list of import objects, press F5 while in the AL editor. The system dis-plays the Symbols survey. Highlight the callIMPORT keyword and press F6.

- Flow: i; Data types: Yes/No

Determines whether the request window will be shown before the import-transaction is started.

These examples show how to start an import transaction. The first exam-ple shows the request window. The second example skips the request win-dow and starts the import transaction immediately.

With a request window

Name := �Consolidation - Database�; {The import transaction}

callIMPORT(Name); {Displays the request window

and then, after the user

selects Start, executes the

import transaction}

Without a request window

Name := �Consolidation - Database�; {The import transaction}

callIMPORT(Name, FALSE); {Executes the import transac-

tion}

Note : If the function is called with the name of a non-existing import object, a run time error will occur.

To... Enter...

Display the request window before the import transaction is started

TRUE or leave blank (default)

Start the import transaction without showing the request window

FALSE

callIMPORT

ImportName

Request

For Example...

Page 57: Guide to the Navision Al Dbms

callMENU

AL Reference Guide 53

Loads and executes a menu object identified by a MenuNo.

callMENU(MenuNo)

- Flow: i; Data types: Number

A number which identifies the menu object. To choose from the list of menu objects, press F5 while in the AL editor. The system displays the Symbols survey. Highlight the callMENU keyword and press F6.

This AL code sample shows how to activate a menu.

MenuNo := 2; {The menu to be displayed}

callMENU(MenuNo); {Activate the menu}

Note : If MenuNo does not exist, a run time error will occur.

callMENU

MenuNo

For Example ...

Page 58: Guide to the Navision Al Dbms

callREPORT

54 ALReference Guide

Loads and executes a report object identified by a ReportName.

callREPORT(ReportName [, Request])

- Flow: i; Data types: String

The name of the desired report object. The string must contain an exact match of the name of the report object (case sensitive). To choose from the list of report objects, press F5 while in the AL editor. The system dis-plays the Symbols survey. Highlight the callREPORT keyword and press F6

- Flow: i; Data types: Yes/No

Determines whether the request window will be shown before the report is started.

These example show how to execute a report. The first example displays the request window. The second example skips the request window and starts the report immediately. Please note that the name string is case sen-sitive, and must contain an exact match of the report object name.

With a request window

ReportName := 'BOM Raw Materials'; {The report name}

callREPORT(ReportName); {Displays the request window

and then, after the user

selects start, executes the

report}

Without a request window

ReportName := 'BOM Raw Materials'; {The report name}

callREPORT(ReportName, FALSE); {Executes the report}

Note : If the report object identified by ReportName does not exist, a run time error will occur.

To... Enter...

Display the request window before the report is started

TRUE or leave blank (default)

To start the report directly FALSE

callREPORT

ReportName

Request

For Example...

Page 59: Guide to the Navision Al Dbms

callSYSTEM

AL Reference Guide 55

Makes it possible to execute external programs and operating system commands from AL programs.

ReturnCode := callSYSTEM(Name [, Param, ...]

- Flow: i; Data types: String

The path and name of the command.

- Flow: i; Data types: String

One or more optional argument(s) to be sent to the operating system com-mand. Each parameter is treated as a substring, that is all parameters are concatenated into one string which forms the argument to the operating system command. This means that if more than one parameter is to be passed to the operating system command, the parameters can be supplied either as individual arguments, or as a string in which the arguments are separated by spaces. The total length of the string(s) cannot exceed 128 characters.

-Flow: o; Data types: Integer

This is a return code from the external program or the operating system command.

External programs can return different codes in order to reflect whether one or more error(s) occured during the execution of the external pro-gram. The possible value of the ReturnCode will depend on the external program.

When using the callSYSTEM command to activate operating system command, the following simple rules apply. DOS commands (DIR, COPY, ...), OS/2 commands (DIR, COPY, ...) and UNIX commands (ls, cd, ...) will always return the value 0 (zero).

When callSYSTEM returns, the screen is automatically updated.

The general format of a callSYSTEM statement is:

callSYSTEM('c:\joe\myprog.exe', 'arg1', 'arg2');

This executes a program named 'myprog.exe' in the directory 'joe' at drive c:. 'arg1' and 'arg2' denotes arguments which are passed to the function.

To call the DOS command DIR, execute the following:

CommandProcessor := 'c:\command.com';

{The path and name of the DOS command processor.}

Argument := '/c';

OsCommand := 'dir';

MESSAGE('Press ENTER to execute the DOS command %1', OsCommand);

WAITKEYPRESS();

callSYSTEM(CommandProcessor, Argument, OsCommand);

In order to execute the corresponding OS/2 command, substitute the com-

callSYSTEM

Name

Param, ...

ReturnCode

General Comments...

For Example...

Page 60: Guide to the Navision Al Dbms

callSYSTEM

56 ALReference Guide

mand processor 'command.com' with 'cmd.exe'.

In order to execute the corresponding UNIX command 'ls', it is not nec-essary to activate a command processor. The following statement is suffi-cient to get a list of the files in the current directory:

callSYSTEM('ls');

Page 61: Guide to the Navision Al Dbms

callWINDOW

AL Reference Guide 57

Loads and executes a window object identified by a WindowNo. All win-dow objects are associated with a specific table and when a window object is executed, one or more records (depending on the type of the win-dow) from this table will be displayed .

Ok:= callWINDOW(WindowNo [, Record] [, Record.Field])

- Flow: i; Data types: Number

A number which identifies the window object.

If callWINDOW is used with WindowNo = 0, the default lookup window for the actual table will be shown. In this case the optional parameter Record must be used, in order to specify the table.

To choose from the list of window objects, press F5 while in the AL edi-tor. The system displays the Symbols survey. Highlight the callWINDOW keyword and press F6

- Flow: i; Data types: Record

The callWINDOW function will as default show the record which was displayed the last time the window was open. For each window object the system stores information about the most recently shown record and the attached key and filters.

This optional parameter is used to select a specific record to be shown in the window. The record must be of the same type as the table associated to the window. When showing the record, the window will use the key and filters attached to the record.

- Flow: i; Data types: RecordField

Is used to position the cursor on a specific field. If this optional parameter is not used, the default cursor position will be either in the upper left of the screen, or the same position as the last time the window was open..

- Flow: o; Data types: Yes/No

For the window objects: List, Tabular, Chart and Card this return code reflects whether the ENTER or ESC was used to quit the window.

Note : If the window object identified by WindowNo does not exist, a run time error will occur.

Note : When a List, Tabular, Chart or Card window object has been called with the optional parameter Record, it is possible to assign values to the fields in the record. This is done by placing the cursor on the primary key field in an arbitrary record. When ENTER is pressed the system returns to the AL code and the values in the record pointed out by the cursor has now been assigned to the fields in Record.

callWINDOW

WindowNo

Record

Record.Field

Ok

Page 62: Guide to the Navision Al Dbms

callWINDOW

58 ALReference Guide

.

The only way to quit the other window objects (Worksheet, Matrix, Sta-tistics and Periodic) is by using ESC, that is, they will always return the value FALSE.

The following examples illustrates how to use the callWINDOW func-tion.

Example 1:

A simple example, which shows how to call window no. 1001.

WindowNo := 1001; {A window object}

callWINDOW(WindowNo); {Activate the window object

with default values for Record

and Record.Field}

Example 2:

Consider the following AL code sample:

dbSELECTKEY(Customer.Name);

dbSETFILTER(Customer.�No.�, �>=2000�);

callWINDOW(1002,Customer);

The window will show customers with “no.” greater than or equal to 2000, sorted by Name. The current key and filters on Customer are never changed when using callWINDOW, as the user operates on a copy of the filters and the current key.

Example 3:

The following construct can be used to detect whether the user pressed ESC or ENTER in the window.

IF callWINDOW(1002,Customer) THEN

MESSAGE(�ENTER was pressed - Customer has changed�)

ELSE

MESSAGE(�ESC was pressed - Customer is unchanged�);

If ENTER was pressed, callWINDOW returns the Customer highlighted in the window.

Example 4:

The AL code sample:

callWINDOW(1002);

will show the same list of customers, use the same sorting sequence, and show the same current customer as last time the window was open. All filters and the current key are fetched from a setup-file.

Ok Means that...

TRUEENTER was used to quit the window. This also selects the record pointed out by the cursor.

FALSE ESC was used to quit the window.

For Example...

Page 63: Guide to the Navision Al Dbms

CLEAR

AL Reference Guide 59

Clears the value of a Variable.

CLEAR(Variable)

- Flow: i; Data types: -

This parameter is an identifier (variable) of any AL datatype (both simple and composite datatypes).

• Number variable will be set to the value 0.

• A String variable will be set to the empty string ''.

• A Date variable will be set to the undefined date 0D.

• A Time variable will be set to the undefined time 0T.

• A Yes/No variable will be set to the value FALSE.

For a composite data type, such as a record or an array all elements will be cleared.

This example shows how to use CLEAR.

Name := 'Joe Blow';

MESSAGE('Initially the variable "Name" contains: >%1<', Name);

CLEAR(Name);

MESSAGE('After using CLEAR the variable "Name" contains: >%1<',

Name);

The first message box will show:

...while the second message box will show:

Initially the variable �Name� contains: >Joe Blow<

After using CLEAR the variable �Name� contains: ><

CLEAR

Variable

For Example...

Page 64: Guide to the Navision Al Dbms

CLEARALL

60 ALReference Guide

Clears all internal variables, keys and filters in the object (function, report, ...) containing the AL code.

CLEARALL()

When a function is called repeatedly within the same transaction, all val-ues for variables and filters are retained in memory between the calls (This is for example used to enumerate entry numbers when booking) . When you do not need the values retained in memory, you can use the CLEARALL() function in order to ensure that all variable are cleared.

Refer to the description of the CLEAR function for a description of initial values in cleared variables.

This function is for example used in function no. 80 (Sales-post) in the NAVISION demo application.

CLEARALL

General Comments...

For Example...

Page 65: Guide to the Navision Al Dbms

CLOSEWINDOW

AL Reference Guide 61

Use this function to close a dialog window which has been opened by OPENWINDOW.

CLOSEWINDOW()

Observe the following:

• If OPENWINDOW has not been called, a run time error will occur.

• Each object (function-, report-, ...) can only have one dialog window open at a time. The system will automatically close an existing dialog window before it opens a new dialog window.

• The system will also close the dialog window automatically when an object is terminated.

This example shows how to use the CLOSEWINDOW function.

OPENWINDOW('This is a window\Sample text no. 1: #1#####\'+

'Sample text no. 2: #2#########');

{Defines a window with 2 fields}

UPDATEWINDOW(1, 'Hello'); {Inserts text in field 1}

UPDATEWINDOW(2, 'out there'); {Inserts text in field 2}

WAITKEYPRESS(); {Pauses until ESC or ENTER is

pressed}

CLOSEWINDOW(); {Close the window}

The window will show:

When you press ESC or ENTER the window will be removed by the CLOSEWINDOW function.

This is a window

Sample text no. 1: Hello

Sample text no. 2: out there

CLOSEWINDOW

General Comments...

For Example...

Page 66: Guide to the Navision Al Dbms

CLOSINGDATE

62 ALReference Guide

Returns the closing date for a Date.

ClosingDate := CLOSINGDATE(Date)

- Flow: i; Data types: Date

The input date.

The figure below illustrates how the system sorts the closing dates between the normal dates for an arbitrary month..

- Flow: o; Data types: Date

The corresponding closing date for Date.

These examples show how to use the CLOSINGDATE function. In the first example a normal date is given as input, and in the second example a closing date is given as input.

A normal date as input.

Date1 := 040496D;

CloDate := CLOSINGDATE(Date1);

MESSAGE('The closing date for %1 is %2', Date1, CloDate);

The message box will show:

A closing date as input.

Date1 := CLOSINGDATE(040496D);

Clodate := CLOSINGDATE(Date1);

MESSAGE('The closing date for %1 is %2', Date1, CloDate);

The message box will show:

Note : All dates have a corresponding closing date. A closing date is regarded by the system as a period following the given date, but before the next normal date, thus closing dates are sorted immediately after the corresponding normal date, but before the next normal date.

If Date is a... Then ClosingDate will be a...

Normal date Closing date

Closing date Closing date

The closing date for 04/04/96 is C04/04/96

The closing date for C04/04/96 is C04/04/96

CLOSINGDATE

Date

April 1994

040194D

xxxxxxC: Closing date

...040194C 040294D 040294C 040394D 040394C

xxxxxxD: Normal date

ClosingDate

For Example...

Page 67: Guide to the Navision Al Dbms

COMPANYNAME

AL Reference Guide 63

Returns the current company name.

Name := COMPANYNAME()

- Flow: o; Data types: String

The company name, or the empty string if a company has not been selected.

When you enter your application, you will be prompted to select a com-pany. The COMPANYNAME function reflects this selection

This example shows how to use the COMPANYNAME function to retrieve the name of the current company.

Name := COMPANYNAME();

{Get the name of the current company}

MESSAGE('The company name is: %1', Name);

{Print the companyname}

COMPANYNAME

Name

General Comments...

For Example...

Page 68: Guide to the Navision Al Dbms

COMPRESSARRAY

64 ALReference Guide

Moves all non-empty strings in an array of strings (StringArray), to the start of the array. In other words the resulting StringArray has the same number of elements as the input array, but empty entries and entries only containing blanks appears at the end of the array. Refer to figure below.

COMPRESSARRAY(StringArray)

- Flow: io; Data types: Array

The string type array to be compressed.

The COMPRESSARRY function is especially useful when printing names and addresses, for instance in statements of accounts where blank lines must be removed.

The following figure illustrates the function of COMPRESSARRAY. The figure shows a StringArray given as input to left, and the corresponding output to the right.

The figure illustrates that all non-empty entries have been moved to the top of the array.

The following AL code sample illustrates how to perform the above com-pression of an array of strings.

Name[1] := ��; {Empty String}

Name[2] := 'Joe Blow';

Name[3] := '1241 East Druid Avenue';

Name[4] := ' '; {A string containing blanks}

Name[5] := 'Chicago';

Name[6] := ��;

MESSAGE('The address before compression, is written as:\' +

'%1\' +

'%2\' +

Note : When compressing an array of strings, the non-empty strings in the resulting array will have the same sorting as in the original array.

COMPRESSARRAY

StringArray

General Comments...

For Example...

‘Joe Blow’

‘1241 East Druid Avenue’

‘ ’

Input Output

COMPRESSARRAY

‘Chicago’

‘Joe Blow’

‘1241 East Druid Avenue’

‘Chicago’

‘’

‘’

‘’

‘’

‘’

Page 69: Guide to the Navision Al Dbms

COMPRESSARRAY

AL Reference Guide 65

'%3\' +

'%4\' +

�%5\� +

�%6�, Name[1], Name[2], Name[3], Name[4], Name[5], Name[6]);

COMPRESSARRAY(Name); {The empty lines (strings) are removed}

MESSAGE('The address after compression, is written as:\' +

'%1\' +

'%2\' +

'%3\' +

'%4\' +

�%5\� +

�%6�, Name[1], Name[2], Name[3], Name[4], Name[5], Name[6]);

The first message-box will show:

The second message-box will show:

The empty and blank strings which caused blank lines, has been moved to the end of the array, and the other elements has been moved up.

Note that an empty string is not printed when it occurs as the last (or the first) line in a message box.

The address before compression, is written as:

Joe Blow

1241 East Druid Avenue

Chicago

The address after compression, is written as:

Joe Blow

1241 East Druid Avenue

Chicago

Page 70: Guide to the Navision Al Dbms

CONFIRM

66 ALReference Guide

Creates a dialog box which prompts for a Yes/No answer. The dialog box is centered at the middle of the screen.

Ok := CONFIRM(String [, Default])

- Flow: i; Data types: String

This string is displayed in the dialog box. Use the '\'character to indicate a new line. The height of the dialog box corresponds to the number of lines, and the width of the dialog box corresponds to the length of the longest substring. A Yes/No prompt field must be inserted in the string by using '#'-characters. Normally 3 '#'-characters are used, as this length matches both 'Yes' and 'No'.

- Flow: i; Data types: Yes/No

Describes what the computer should use as default in the Yes/No field. If the variable Default is not specified, the value 'No' will be used.

- Flow: o; Data types: Yes/No

The return parameter reflects the user's selection:

In the following example the CONFIRM function is used to prompt the user for a Yes / No answer:

Question := 'Leave without saving changes? ###';

{A string containing a #-field for a Yes/No prompt}

Answer := CONFIRM(Question, TRUE);

MESSAGE(�You selected %1�, Answer);

Note : A run time error will occur if String does not contain a '#'-field.

Ok will be... If you entered...

TRUE Yes

FALSE No

CONFIRM

String

Default

Ok

For Example...

Page 71: Guide to the Navision Al Dbms

CONVERTSTR

AL Reference Guide 67

Converts the characters in a String according to the characters in the two strings FromCharacters and ToCharacters, which serves as conversion tables.

Example: If FromCharacters[1] is found in String[x] then String[x] is set to ToCharacters[1]. If FromCharacters[2] is found in String[y] then String[y] is set to ToCharacters[2] and so on.

NewString := CONVERTSTR(String, FromCharacters, ToCharacters)

- Flow: i; Data types: String

The string to be converted.

- Flow: i; Data types: String

A string describing which characters to be replaced. The CONVERTSTR function is case-sensitive.

- Flow: i; Data types: String

A string describing the new characters to be inserted. The CONVERT-STR function is case sensitive. The length of this string must correspond to the length of FromCharacters. If the length of the FromCharacters and ToCharacters strings both are 0, (empty strings) no changes are made.

- Flow: o; Data types: String

The converted string.

The following shows how to use the CONVERTSTR function

OriginalString := 'Want to leave without saving?';

FromChars := 'lws';

ToChars := 'LWS';

NewString := CONVERTSTR(OriginalString, FromChars, ToChars);

MESSAGE('The original sentence is:\ %1', OriginalString);

MESSAGE('The sentence is converted to:\ %1', NewString);

The first message box will show:

...while the second message box will show:

Note : If the lengths of the FromCharacters and ToCharacters strings are not equal, a run time error will occur.

The original sentence is:

Want to leave without saving?

The sentence is converted to:

Want to Leave Without Saving?

CONVERTSTR

String

FromCharacters

ToCharacters

NewString

For Example...

Page 72: Guide to the Navision Al Dbms

COPYARRAY

68 ALReference Guide

Copies one or more elements from an Array to a NewArray.

NewArray := COPYARRAY(Array, Position [, Length])

- Flow: i; Data types: Array

The array to be copied from. Copying can only take place from one-dimensional arrays. Two- and three-dimensional arrays can be copied by repeated use of the COPYARRAY function.

- Flow: i; Data types: Number

The position of the first array-element to be copied.

- Flow: i; Data types: Number

The number of array elements to be copied. Valid values for Length are:

1 ≤ Length ≤ MAXLEN(Array) - Position + 1

If Length is not specified, all array elements from Position to the last ele-ment will be copied.

- Flow: o; Data types: Array

The resulting array is one-dimensional.

The following two examples show how to use the COPYARRAY func-tion. The first example shows how to copy three elements from a one dimensional array. The second example shows how to copy two and three dimensional arrays.

How to copy from a one-dimensional array.

{Old has been defined as a one-dimensional array with size 5, and

{New has been defined as a one-dimensional array with size 3}

Old[1] := 'Joe';

Old[2] := 'Blow';

Old[3] := 'lives';

Old[4] := 'in';

Old[5] := 'Chicago';

New := COPYARRAY(Old,3);

MESSAGE('The contents of the Old array is:\' +

'1: %1 \' +

'2: %2 \' +

'3: %3 \' +

'4: %4 \' +

'5: %5', Old[1], Old[2], Old[3], Old[4], Old[5]);

MESSAGE('The contents of the copied array is:\' +

'1: %1 \' +

'2: %2 \' +

'3: %3 \', New[1], New[2], New[3]);

COPYARRAY

Array

Position

Length

NewArray

For Example...

Page 73: Guide to the Navision Al Dbms

COPYARRAY

AL Reference Guide 69

The first message box will show the following:

... while the second message box will show the following:

How to copy from a two or three dimensional array.

It is possible to copy two and three dimensional array by repeated used of the COPYARRAY function. This example shows one way to copy a (small) two dimensional array by using two COPYARRAY statements.

{Assume that the Arr and New arrays both are 2x2 Integer arrays}

Arr[1,1] := 11;

Arr[1,2] := 12;

Arr[2,1] := 21;

Arr[2,2] := 22;

New[1] := COPYARRAY(Arr[1], 1);

New[2] := COPYARRAY(Arr[2], 1);

MESSAGE(�The resulting array: \� +

�(%1) (%2) \� +

�(%3) (%4)�, New[1,1], New[1,2], New[2,1], New[2,2]);

The message box will show:

When using COPYARRAY to copy large two or three dimensional arrays you should use one of the looping constructs available in AL.

The contents of the Old array is:

Joe

Blow

lives

in

Chicago

The contents of the copied array is:

lives

in

Chicago

The resulting

array:

(11) (12)

(21) (22)

Page 74: Guide to the Navision Al Dbms

COPYSTR

70 ALReference Guide

Copies a sub-string of any Length from a specific Position in a String to a NewString.

NewString := COPYSTR(String, Position [, Length])

- Flow: i; Data types: String

The string to be copied from.

- Flow: i; Data types: Number

The position of the first character to be copied. The value of Position must be greater than 0. If Position is greater than STRLEN(String) then an empty string will be returned by COPYSTR.

- Flow: i; Data types: Number

The number of characters to be copied. Length must be greater than 0. If the value of Length causes that:

Position + Length > STRLEN(String)

then the resulting string will be all characters from Position to the end of the string.

If Length is not specified, the resulting string will be all characters from Position to the end of the string.

- Flow: o; Data types: String

The resulting (sub-)string.

This shows how to use the COPYSTR function.

Str := 'Using the COPYSTR function';

Position := 7;

Length := 8;

MESSAGE('The original string is:\>%1<', Str);

NewStr := COPYSTR(Str, Position, Length);

MESSAGE('The copied string is: \>%1<', NewStr);

The first message-box shows the original string:

...while the second message-box will show the copied (sub-)string:

The original string is:

>Using the COPYSTR function<

The copied string is:

>the COPY<

COPYSTR

String

Position

Length

NewString

For Example...

Page 75: Guide to the Navision Al Dbms

DATE2DMY

AL Reference Guide 71

Returns the day, month and year based on a Date.

Number := DATE2DMY(Date, What)

- Flow: i; Data types: Date

The input date.

- Flow: i; Data types: Number

Specifies what the function should return. The valid values are 1, 2 and 3:

- Flow: o; Data types: Integer

The resulting output day, month or year.

The following shows how to use the DATE2DMY function.

D := 120190D;

Day := DATE2DMY(D, 1); {Get the date}

Month := DATE2DMY(D, 2); {Get the month no.}

Year := DATE2DMY(D, 3); {get the year}

MESSAGE('The date %1, corresponds to:\' +

'Day no. %2 in\' +

'month no. %3 in\' +

'the year %4 \', D, Day, Month, Year);

The message box will show the following:

What Corresponds to...

1 Day (1-31).

2 Month (1-12).

3 Year (1980 - 2059).

The date 12/01/90 corresponds to:

Day no. 1 in

month no. 12 in

the year 1990

DATE2DMY

Date

What

Number

For Example...

Page 76: Guide to the Navision Al Dbms

DATE2DWY

72 ALReference Guide

Returns the day of the week, week number and year based on the input Date.

Number := DATE2DWY(Date, What)

- Flow: i; Data types: Date

The input date.

- Flow: i; Data types: Number

Specifies what the function should return. The valid values are 1, 2 and 3:

- Flow: o; Data types: Integer

The resulting day of the week, week number or year.

A special situation occurs if the input date to the DATE2DWY function is in a week which overlaps two years. The DATE2DWY function computes the output year as the year of the first day in this week. This is illustrated in the example below.

The following illustrates a special case which occures when using the DATE2DWY function in a week which overlaps two years.

D := 010194D;

DayOfWeek := DATE2DWY(D, 1);

WeekNumber := DATE2DWY(D, 2);

Year := DATE2DWY(D, 3);

MESSAGE('The date %1, corresponds to:\' +

'The day of the week: %2\' +

'The week number: %3\' +

'The year: %4', D, DayOfWeek, WeekNumber, Year);

The message box will show:

The example illustrates that the system regards the date 01/01/94 as day no. 6 (Saturday) in week no. 52 in the year 1993!

What Corresponds to...

1 day of the week (1-7, Monday = 1).

2 week number (1-53).

3 year (1980 - 2059).

The date 01/01/94, corresponds to:

The day of the week: 6

The week number: 52

The year: 1993

DATE2DWY

Date

What

Number

General Comments...

For Example...

Page 77: Guide to the Navision Al Dbms

dbCALCFIELDS

AL Reference Guide 73

Updates Calculated fields in a record

dbCALCFIELDS(Record.Field [, Record.Field, ...])

-Flow: io; Datatypes: RecordField

Fields that are to be updated. Each field must be defined as a Calculated field. All fields must belong yo the same record variable.

The Caluclated fields are of Yes/No or Decimal No. type. Calculated fields are a special NAVISION feature which provides information about other tables in the database in the same company. A Calculated field of type Decimal No. holds sums accumulated from columns in other tables, while Calculated fields of type Yes/No confirms whether records exist within a specified range in another table.

Calculated fields are virtual fields, as their values are not saved with the table. Calculated fields require that dbCALCFIELDS are called in order to be updated.

For example, Calculated fields in records fetched with dbFINDREC and dbNEXTREC are set to zero. A call to dbCALCFIELDS are needed to update their values. A detailed explanation of calculated fields can be found in “The NAVISION DBMS”.

The following AL code sample shows how to use the dbCALCFIELDS function. We show how to find the balance at December 31, 1994 and the movement for a customer in 1994:

dbSETRANGE(Customer.�Date Filter�,010194D,123194D);

dbCALCFIELDS(Customer.Balance, Customer.Movement);

The first line sets up a delimitation for the field “Date Filter” in the record Customer. This field is a Calculation Filter field which is used in the computation of some of the Calculated fields in Customer. The computa-tion of the Calculated fields is then carried out using dbCALCFIELDS in the second line.

dbCALCFIELDS

Record.Field

General Comments...

For Example ...

Page 78: Guide to the Navision Al Dbms

dbCALLFIELDCODE

74 ALReference Guide

Calls the Entry Processing code for the field Rec.Field.

dbCALLFIELDCODE(Record.Field [, Value])

- Flow: io; Datatypes: RecordField

A field with associated Entry Processing code.

Flow: i; Datatypes:-

The optional parameter Value is used to assign a value to the field before the entry processing takes place. The type of Value must match the type of Record.Field.

The following AL code sample illustrates the use of the dbCALLFIELD-CODE function.

When an account no. is entered in a ledger, some entry processing code must be activated in order to, for example, transfer the name of the account from the chart of accounts.

If an account no. is entered in a batch, the code which transfers the name of the account will not automatically be executed. The following causes the appropriate code to be executed:

dbCALLFIELDCODE(GeneralLedgerLine.AccountNo, �100�);

This corresponds to:

GeneralLedgerLine.AccountNo := �100�;

dbCALLFIELDCODE(GeneralLedgerLine.AccountNo);

dbCALLFIELDCODE

Record.Field

Value

For Example ...

Page 79: Guide to the Navision Al Dbms

dbCOMMIT

AL Reference Guide 75

Confirms updates made to the database.

dbCOMMIT()

The dbCOMMIT() function is used to explicitly commit an update to the database. When the system enters an AL code module it automatically enables write transactions to be performed, and when the system exits the AL code module it automatically ends the write transaction by commit-ting the update(s) made by the AL code. This means that if the AL code module only is to perform a single write transaction, then the update is automatically committed. But if the AL code module is to perform several write transactions, then dbCOMMIT() must be used to explicitly end one write transaction, before the next can be started. In other words: the dbCOMMIT function separates the write transactions in an AL code mod-ule.

See “The NAVISION DBMS” for a detailed discussion about committing database updates.

Figure 1 illustrates how to use the dbCOMMIT function. The AL code contains two write transactions. As the execution of the AL code begins, a write transaction is automatically started. By issuing the command dbCOMMIT(), you tell the system that the first write transaction has ended, and prepares the system for the second. As the execution of the AL code has been completed, the system automatically ends the second write transaction.

dbCOMMIT

General Comments...

For Example ...

BeginWriteTransaction

AL Module

AL Statements

dbCommit(...)

}}

1. Trans.

2. Trans.

EndWriteTransaction

AL Statements

Figure 1. Com-mitting updates

in AL code

Page 80: Guide to the Navision Al Dbms

dbCONSISTENT

76 ALReference Guide

Marks a table as being consistent or inconsistent according to an adminis-trative point of view.

dbCONSISTENT(Record, Consistent)

- Flow: i; Datatypes: Record

The table to marked.

- Flow: i; Datatypes: Yes/No

A mark to be set on Table.

Normally this function is only used for accounting routines.

If your accounts do not balance, the accounts are inconsistent. dbCON-SISTENT is used to assure that no inconsistent changes are made to your accounts

If an attempt is made to commit a write transaction when a table is marked as inconsistent, an error message will occur, and all updates made in the write transaction is aborted.

A typical example of inconsistency is if the sum of all the entries in a table containing finance entries does not balance (that is, not zero).

Imagine that your application includes a function object: ChangeAmount. This function is used to withdraw respectively put in amounts in the FinanceEntry table in your application. When an amount is withdrawn from an account, the system is inconsistent until a corresponding amount is put in. The pseudo code below illustrates the ChangeAmount function.

The function uses a variable Balance to express the change in balance. When the function is used to withdraw for example $100, the Balance variable will reflect this as -$100. When the function is used to put in one

To... Enter...

Mark the table as consistent. TRUE

Mark the table as inconsistent. FALSE

dbCONSISTENT

Record

Consistent

General Comments...

For Example...

FUNCTION ChangeAmount(DecimalNo.: Amount) BEGIN

GLEntry.�G/L Account No.� := �1000�;

GLEntry.Amount := Amount;

dbINSREC(GLEntry);

Balance := Balance + Amount;

IF Balance = 0 THEN

Consistent := TRUE

ELSE

Consistent := FALSE;

dbCONSISTENT(GLEntry, Consistent);

END; {ChangeAmount}

Page 81: Guide to the Navision Al Dbms

dbCONSISTENT

AL Reference Guide 77

or more amounts which sum up to +$100, the Balance variable will equal zero, and the table will be marked as consistent. This means that if an attempt is made to put in an amount and end the write transaction (com-mit the change) without withdrawing a corresponding amount within the same transaction, an error will occur, and the write transaction will be aborted.

Page 82: Guide to the Navision Al Dbms

dbCOPYALLFILTERS

78 ALReference Guide

Copies all filters set by dbSETFILTER/dbSETRANGE and the state of dbMARKEDONLY from one record to another.

dbCOPYALLFILTERS(FromRecord, ToRecord)

- Flow: i; Datatypes: Record

The filters are copied from this record.

- Flow: o; Datatypes: Record

The filters are copied to this record.

This function is used to apply filters defined for another record, as basis for a counting, a search, calculation or similar operations.

This AL code sample shows how to use the dbCOPYALLFILTERS func-tion.

dbSETFILTER(CustomerRec1.�No.�, �<1000�); {Set various}

dbSETRANGE(CustomerRec1.Group, 1); {filters on fields}

dbMARKEDONLY(CustomerRec1, TRUE); {in a Customer record}

dbCOPYALLFILTERS(CustomerRec1, CustomerRec2);{Apply the same}

. {filters to another}

. {record}

Count := dbRECCOUNT(CustomerRec2);

The filters defined for CustomerRec1 is copied, and applied to CustomerRec2 and affects the result returned by the dbRECCOUNT function in the last line.

dbCOPYALLFILTERS

FromRecord

ToRecord

General Comments...

For Example...

Page 83: Guide to the Navision Al Dbms

dbCOPYFILTER

AL Reference Guide 79

Copies the filter set for one field and applies it to another field.

dbCOPYFILTER(FromRecord.FromField, ToRecord.ToField)

- Flow: i; Datatypes: RecordField

The filter set for this field is copied.

- Flow: o; Datatypes: RecordField

The filter copied from FormRecord.FromField is applied to this field.

The FromFields and Tofields must be of the same data type, but does not need to belong to the same table.

This AL code sample illustrates how to use the dbCOPYFILTER function

dbSETFILTER(Customer.�No.�, �<1000�);

dbCOPYFILTER(Customer.�No.�, Vendor.�No.�);

.

.

Count := dbRECCOUNT(Vendor);

The filter set for Customer.”No.” is copied and applied to Vendor.”No.”. This again affects the result of the dbRECCOUNT function, which counts the number of vendors with a number less than 1000.

dbCOPYFILTER

FromRecord.FromField

ToRecord.ToField

General Comments...

For Example...

Page 84: Guide to the Navision Al Dbms

dbDELALL

80 ALReference Guide

Deletes all records within a specified range in a table.

dbDELALL(Record)

- Flow: io; Datatypes: Record

Identifies the table in which the deletion will take place. Only records within the range specified by the filters set for Record will be deleted.

This AL code sample illustrates the function of the dbDELALL function.

WHILE dbFINDREC(Customer, �-�) DO

dbDELREC(Customer);

The above code performs the same operation as:

dbDELALL(Customer);

But the dbDELALL function is much faster, as only one access to the server is needed, while the first method requires multiple accesses to be performed.

dbDELALL

Record

For Example...

Page 85: Guide to the Navision Al Dbms

dbDELREC

AL Reference Guide 81

Deletes a record in a table.

[Ok :=] dbDELREC(Record)

-Flow: i; Datatypes: Record

The record to be deleted. Record itself does not change.

- Flow: o; Data types: Yes/No

The return value. If the record does not exist, the function will terminate with a run time error, if this optional return value is not used.

This function deletes a record from a table. The current key and any filters bound to the record have no effect on this operation. The record to be deleted is identified only by the values in its primary key.

In a multi-user environment, another application can delete the record from the table in the interval between your reading of the record, and your attempt to delete it. The NAVISION DBMS automatically detects if such a situation occurs, which causes dbDELREC to fail with a run time error .

To prevent this situation, you can explicitly lock the table by using dbLOCKTABLE. This causes the table to be locked the entire time during your operation on the table, preventing other users to acces the table. Refer to the “NAVISION DBMS” for further information about table locking.

These AL code samples illustrate how to use the dbDELREC function. The first example does not use the return value from the dbDELREC function. This means that a run time error will occur if the record to be deleted cannot be found. The second example shows how the programmer explicitly can take care of the error handling by using the return value.

Without using the return value:

Customer.�No.� := �100�:

dbDELREC(Customer);

Using the return value:

Customer.�No.� := �100�;

IF dbDELREC(Customer) THEN

MESSAGE(�The customer has been deleted�)

ELSE

ERROR(�The customer could not be found�);

If Ok is... It means that...

TrueThe record was successfully deleted

FalseThe record was not found in the table.

dbDELREC

Record

Ok

General Comments...

For Example...

Page 86: Guide to the Navision Al Dbms

dbFIELDACTIVE

82 ALReference Guide

Checks whether a field is active or not, that is, whether the field can be used or not.

Ok := dbFIELDACTIVE(Record.Field)

- Flow: i; Datatypes: RecordField

The field to be checked.

- Flow: o; Datatypes: Yes/No

This return value reflects whether the field was marked as active or in-active.

Each field in a record can be set as active or inactive in the table descrip-tion for the table in question. An inactive field cannot contain data.

The following AL code sample shows how to use the dbFIELDACTIVE function.

The statement:

Customer.�Address 2� := �Atlanta�;

causes a run time error, if the field “Address 2” has not been marked as active. This run time error could be avoided by performing the following test:

IF dbFIELDACTIVE(Customer.�Address 2�) THEN

Customer.�Address� := �Atlanta�

ELSE

MESSAGE(�The field is not marked as active�);

If Ok is... It means that...

TRUE The field is marked as active

FALSE The field is marked as in-active

dbFIELDACTIVE

Record.Field

Ok

General Comments...

For Example...

Page 87: Guide to the Navision Al Dbms

dbFIELDERROR

AL Reference Guide 83

Creates an error message for a field, and stops the execution of the code.

dbFIELDERROR(Record.Field [, Text])

- Flow: i; Domain: RecordField

The input field.

- Flow: i; Domain: String

This optional parameter is used to hold text to be printed as part of an error message.

Like with any other run time error, this function will cause any transaction to be aborted automatically.

The following three AL code samples illustrate how to use the dbFIELD-ERROR function.

Without using the Text parameter:

Customer.�No.� := ��;

dbFIELDERROR(Customer.�No.�);

This will show the following:

Without using the Text parameter:

Customer.�No.� := �NEW 3500�;

dbFIELDERROR(Customer.�No.�);

This will show the following::

Using a non-empty string as Text parameter:

Customer.�No.� := �NEW 3500�;

dbFIELDERROR(Customer.�No.�, �is not specified�);

This will show the following::

You must specify �No.�

in the below Customer

No. cannot be NEW 3500

in the below customer

NEW 3500

�No.� is not specified

in the below Customer

NEW 3500

dbFIELDERROR

Record.Field

Text

General comments...

For Example...

Page 88: Guide to the Navision Al Dbms

dbFIELDNAME

84 ALReference Guide

Returns the name of a field as a string.

String := dbFIELDNAME(Record.Field)

- Flow: i; Domain: RecordField

A field in a record.

- Flow: o; Domain: String

The name of the field given as input.

The following AL code samples show how to use the dbFIELDNAME function.

The statement:

Name := dbFIELDNAME(Customer.�No.�);

The name of a field identifier is stored in a string. The advantage of the above statement over:

Name := �No.�;

is that the first statement dynamically adapts to any changes of field names made in the development system, while the second statement per-forms a static assignment.

dbFIELDNAME

Record.Field

String

For Example...

Page 89: Guide to the Navision Al Dbms

dbFIELDNO

AL Reference Guide 85

Returns the number of a field.

FieldNo := dbFIELDNO(Record.Field)

- Flow: i; Domain: RecordField

The input field

- Flow: o; Domain: Number

The number of the input field.

The following AL code sample shows how to use the dbFIELDNO func-tion. The statement:

Number := dbFIELDNO(Customer.�No.�);

Causes the value 1 to be assigned to the Number variable.

This function is normally used to investigate which field a variable, con-taining a field number, points out in a record:

CASE CurrentFieldNo OF

dbFIELDNO(Customer.�No.�): ...

dbFIELDNO(Customer.Name): ...

dbFIELDNO(Customer.Address): ...

ELSE ...

END;

This construct enables appropriate actions to be taken according to which field number the CurrentFieldNo variable contains.

dbFIELDNO

Record.Field

FieldNo

For Example...

Page 90: Guide to the Navision Al Dbms

dbFINDREC

86 ALReference Guide

Finds a record in a table based on the values in key fields in the records.

[Ok :=] dbFINDREC(Record [, Which])

- Flow: io; Domain: Record

On input Rec points out the record to be found. On output there are two possibilities:

- Flow: i; Domain: String

Specifies how the search is to be performed. The search continues through the table until either the record is found or there are no more records. Each character in the Which string can be present only once. The ‘=’, ‘<‘ and ‘>’ characters can be combined mutually:

-Flow: o; Domain: Yes/No

If this optional return value is not used, a run time error occurs if the record could not be found. When the return value is used, it is assumed that the programmer takes care of the error handling. The return value can take the following values:

dbFINDREC retrieves the first record that meets the conditions set by SearchStr and the s filters associated with Rec. The search path corre-

Was the record found? Then...

Yes

The found record is returned in Record. Any calculated fields used in this record is set to zero, and must be updated by dbCAL-CFIELDS.

NoIf the return value Ok is not used, a run time error will occur.

SearchStr Causes the function to search for ...

'=' A record that equals the key values.(Default)

'>' A record that is larger than the key values.

'<' A record that is less than the key values.

'+'The last record in the table. (‘+’ can only be used alone)

'-'The first record in the table. (‘-’ can only be used alone)

Note : If SearchStr contains any of the characters ‘=’, ‘>’ or ‘<‘, then values must be assigned to all fields of the current key and primary key prior to the call of dbFINDREC.

Ok Means that...

TRUE The record was found.

FALSE The record could not be found.

dbFINDREC

Record

Which

Ok

General Comments...

Page 91: Guide to the Navision Al Dbms

dbFINDREC

AL Reference Guide 87

sponds to the sorting defined by the current key. If the current key is not the primary key, there is a chance that several values have the same values in the current key fields. In this case the sorting order defined by the pri-mary key is used as search path.

The following AL code sample illustrates how to use the dbFINDREC function.

OPENWINDOW(�Search for a customer number:\� +

�#1##################�);

WINDOWINPUT(1, Customer."No.");

IF dbFINDREC(Customer) THEN

MESSAGE(�The record was found!\� +

�Customer No. %1 corresponds to:\� +

�%2�, Customer."No.", Customer.Name)

ELSE

MESSAGE(�Sorry, the record could not be found...�);

First the system prompts you to enter a customer number to search for:

If you enter a customer number that does not exist, for example ‘NOBODY’, the system will display the following message:

If you enter a customer number that exists in the Customer table, for example ‘AAA 1050’, the system will display the following message:

Search for a customer number:

____________________________

Sorry, the record could not be found...

The record was found!

Customer number AAA 1050 corresponds to:

AAA Furniture Manufacturing

For Example...

Page 92: Guide to the Navision Al Dbms

dbGETALLFILTERS

88 ALReference Guide

Returns a string containing the filters for all fields in a record.

String := dbGETALLFILTERS(Record)

-Flow: i; Domain: Record

The input record.

-Flow: o; Domain: String

A string containing filters for all fields in Rec.

The following Al code sample illustrates the use of the dbGETALLFIL-TERS function.

dbSETRANGE("Cust. Ledger Entry".Amount, -100, 100);

dbSETRANGE("Cust. Ledger Entry".Date, 010194D, 123194D);

Str := dbGETALLFILTERS("Cust. Ledger Entry");

MESSAGE(�The filters are:\� +

�%1�, Str);

The message box will show:

The filters are:

Amount:-100..100, Date:010194..123194

dbGETALLFILTERS

dbFINDRECRecord

String

For Example...

Page 93: Guide to the Navision Al Dbms

dbGETCURREC

AL Reference Guide 89

Retrieves a record, marked as current, from the Object Stack.

[OK :=] dbGETCURREC(Record [, Primary])

- Flow: o; data types: Record

The resulting record.

- Flow: i; Domain: Yes/No

The optional parameter Primary is used to specify whether Record is to originate from from the primary object, or from the secondary objects..

- Flow: o; Domain: Yes/No

If this optional return value is not used, a run time error occurs if a record marked as current could not be found. When the return value is used, it is assumed that the programmer takes care of the error handling. The return value can take the following values.

Each object used by your application is assigned a separate area of the internal Object Stack. The Object Stack is a piece of computer memory set aside for storing the variables used inside the objects in your application at run time.

Figure 2 illustrates the Object Stack. In this case the first object on the Object Stack is a Window object. From this Window object a Report object is called. Then again a Function object and so on. Records marked as current are indicated by an ‘x’ in the left column. (Note that the record in a window object is automatically marked as current by the system).

The areas for each object can be seen as sub-stacks in which the variables used in the object are pushed when they are used. The allocation order order in these sub-stacks are from top to bottom.

dbGETCURREC retrieves a variable (record) marked as current, with dbSETCURREC, from the Object Stack.

The parameter Primary determines in which activity the search for Record should take place, or in other words determines the scope of objects to be searched through. When Primary is TRUE only the active object is

If... Enter...

The record must originate from the primary activity

TRUE

The record may originate from secondary activities

FALSE or leave blank (Default)

If Ok is... It means that...

TRUEA record marked as current was found.

FALSEA record marked as current could not be found.

dbGETCURREC

Record

Primary

Ok

General Comments...

Page 94: Guide to the Navision Al Dbms

dbGETCURREC

90 ALReference Guide

searched, whereas FALSE causes the entire Object Stack to be searched from top to bottom.

The following illustates how the dbGETCURREC function searches the Object Stack.

Assume that the object at the top of the Object Stack executes the follow-ing Entry processing code:

.

.

dbGETCURREC(Customer);

dbGETCURREC(Vendor);

.

.

This will cause the system to search the Object Stack from top to bottom. Figure 3 illustrates an Object Stack holding information about four arbi-trary objects, named A, B, C and D.

The search for a Customer record marked as current, will return Customer1 from object A, while the search for a Vendor record marked as current, will return Vendor2 from object B.

Note : When the entire Object Stack is searched, the function will return the record variable which is found first and is marked as current.

Figure 2. TheObject Stack.

Object Stack

Report

Vendor1Window

Function

Se

arch

dir

ect

ion

Window

x

x

x

Vendor2

Customer1Customer2Customer3

Customer1

Automaticallymarked as current

Vendor2

Function

Allocationorder

x

Customer1

(Bottom of Object Stack)

Vendor1

For Example...

Page 95: Guide to the Navision Al Dbms

dbGETCURREC

AL Reference Guide 91

Another example:

Assume that Window no. 1 (W1) is related to Table no. 1 (T1), and that Window no. 2 (W2) is related to Table no. 2 (T2). Records in T1 and T2 are called R1 and R2.

Furthermore we assume that W2 is called from W1; thus the active win-dow will be W2. Text is being typed into W2 which causes the connected Entry processing code to be activated.

Entry processing code for T2:

dbGETCURREC(R2,TRUE) Returns the record R2 on which

the cursor is placed in W2.

dbGETCURREC(R2,FALSE) Returns the record R2 on which

the cursor is placed in W2.

dbGETCURREC(R1,FALSE) Returns the record R1 on which

the cursor is placed in W1.

dbGETCURREC(R1,TRUE) Results in a run-time error as

R1 does not belong to the T2

table with the current window

W2.

OK:=dbGETCURREC(R1,TRUE) Returns the value OK=FALSE.

Object Stack

(x) Customer1

(x) Vendor1

(x) Customer2

(x) Vendor2

Customer3

Sea

rch

orde

r Vendor2

(x) Customer1

Area for object A

Area for object B

Area for object C

Area for object D

Figure 3. Anobject Stack hold-ing record valuesfor four arbitrary

objects.

Page 96: Guide to the Navision Al Dbms

dbGETFILTER

92 ALReference Guide

Returns a text string containing the filter for a field.

String := dbGETFILTER(Record.Field)

-Flow: i; Datatypes: RecordField

The input field.

-Flow: o; Datatypes: String

An output string containing the filter for the input field.

Se also dbSETFILTER and dbSETRANGE.

The following AL code sample shows how to use the dbGETFILTER function.

dbSETRANGE(CustomerEntry.Amount, -100, 100);

Str := dbGETFILTER(CustomerEntry.Amount);

MESSAGE(�The filter is:\� +

�%1�, Str);

The message box will show:

The filter is:

-100..100

dbGETFILTER

Record.Field

String

General Comments...

For Example...

Page 97: Guide to the Navision Al Dbms

dbGETREC

AL Reference Guide 93

Finds a record based on values in a primary key field.

[Ok :=] dbGETREC(Record [, Value, ...])

- Flow: o; Domain: Record

The record found in the table.

- Flow: i; Domain: -

Denotes the value(s) in the primary key fields . The type of Value(s) must match the type of the corresponding primary key field(s). Unspecified fields are assigned the value 0 or an empty string.

- Flow: i; Domain: Yes/No

If this optional return value is not used, a run time error occurs if the record could not be found. When the return value is used, it is assumed that the programmer takes care of the errror handling. The return value can take the following values

The function always uses the primary key for the table and ignores filters, if any. After the function call, the current key and filters are not changed.

The following AL code sample shows how to use the dbGETREC func-tion. The following statement:

dbGETREC(Customer, '1120');

will cause a run time error if the customer with the number 1120 cannot be found. In order to avoid this, use the following construct:

IF dbGETREC(Customer, �1120�) THEN

MESSAGE(�The record was found�)

ELSE

MESSAGE(�Sorry, the record could not be found...�);

If Ok is... It means that...

TRUE The record was found.

FALSE The record could not be found.

dbGETREC

Record

Value,...

Ok

General Comments...

For Example...

Page 98: Guide to the Navision Al Dbms

dbGLOBALFILTER

94 ALReference Guide

Makes filters assigned to a table global.

dbGLOBALFILTER(Record)

- Flow: i; Data types: Record

A record from the table to which filters already are assigned. Any filters assigned to the fields in the record are made global.

Normally the dbGLOBALFILTER function is used only to control special accounting matters.

A global filter is active from the point in time when dbGLOBALFILTER is called, and until the system exits the AL code module containing the function.

In an AL code module a global filter can be temporarily removed by set-ting other filters which overwrites the global filter or by removing all fil-ters using dbRESETTABLE(Record, TRUE).

When the system exits the AL code module, the global filters will, how-ever, be reset to the original. Please note that a global filter only can be changed from within the AL code. Thus, it is not possible for the end user to change the filter in for example a window. Futhermore it is not possible for the end user to see the current global filter.

A global filter is associated to a specific company. If you use dbSELECT-COMPANY(Record, Company) to select a new company, any filters set on Record in the initial company will be transferred to Record. But if one or more of the filters have status as global filters, this status will be removed.

When you return to the initial company, the status is automatically rees-tablished for the global filters on Record. If, in the meantime, the filters for Record were removed, the global filter must be reestablished by dbRESETTABLE(Record, FALSE).

The following shows how to use the dbGLOBALFILTER function

We assume that you want to prevent users from seeing G/L entries outside the range: January 1, 1994 to December 31, 1994. Then you can add the following to Function 1 in your application:

dbSETRANGE(�G/L Entry�.Date,'010194','123194');

dbGLOBALFILTER(�G/L Entry�);

callMENU(MainMenu);

Now the user will not be able to see G/L entries outside the specified range in the chart of accounts, reports, batch jobs and so on.

dbGLOBALFILTER

Record

General Comments...

For Example...

Page 99: Guide to the Navision Al Dbms

dbINITREC

AL Reference Guide 95

Initializes a record.

dbINITREC(Record)

- Flow: io; Data types: Record

The record to be initialized. The dbINITREC function assigns default val-ues to each field in the record. The values correspond to those defined when the table was created . Fields for which no values were defined, are assigned the following default values:

After this operation, you are free to change the values in any or all of the fields before calling dbINSREC to enter the record in the table. Be sure that the field(s) comprising the primary key contain values that make the total primary key unique. If the primary key is not unique (record already exists), the DBMS will reject the record.

These AL code samples shows how to use the dbINITREC function. Assume that the primary key includes the “No.” field. Consider the fol-lowing situations:

Situation 1:

dbINITREC(Customer);

Customer.�No.� := �1120�;

dbINSREC(Customer);

Situation 2:

Customer.�No.� := �1120�;

dbINITREC(Customer);

dbINSREC(Customer);

As dbINITREC does not initialize the primary key fields, the sequence of the statements in situation 1 and 2 is not important. Situation 1 causes the same result as situation 2.

Data type... Default value...

Yes/No No

Option 0

Integer 0

Long Integer 0

Decimal No. 0.0

Date 0D (Undefined date)

Time 0T (Undefined time)

Code '' (empty string)

Text '' (empty string)

Note : The primary key fields are not initialized.

dbINITREC

Record

General Comments...

For Example...

Page 100: Guide to the Navision Al Dbms

dbINSREC

96 ALReference Guide

Inserts a record in a table.

[OK :=] dbINSREC(Record)

- Flow: i; Datatypes: Record

The record to be inserted. Rec itself does not change.

- Flow: o; Datatypes: Yes/No

If this optional return value is not used, a run time error occurs if the record could not be inserted. When the return value is used, it is assumed that the programmer takes care of the errror handling. The return value can take the following values

A record is uniquely identified by the values of the primary key fields. The NAVISION DBMS inspects the primary key for the table before inserting a new record.

The following AL code samples show how to use the dbINSREC func-tion.

Without using the return value:

dbINITREC(Customer);

Customer.�No.� := �1120�;

dbINSREC(Customer);

If for example the customer number 1120 already exists, a run time error will occur. In order to avoid this, use the following construct:

Using the return value:

dbINITREC(Customer);

Customer.�No.� := �1120�;

IF dbINSREC(Customer) THEN

MESSAGE(�Customer no.: %1 inserted�, Customer.�No.�)

ELSE

MESSAGE(�Sorry, an error occured...�);

If Ok is... It means that...

TRUE The record was inserted.

FALSE The record could not be inserted.

dbINSREC

Record

Ok

General Comments...

For Example...

Page 101: Guide to the Navision Al Dbms

dbLOCKTABLE

AL Reference Guide 97

Locks a table to protect it from conflicting write transactions.

dbLOCKTABLE(Record [, Wait] [, VersionCheck])

-Flow: i; Datatypes: Record

A record from the table to be locked.

- Flow: i; Datatypes: Yes/No

The Wait parameter specifies what action to take in case the table already is locked:

- Flow: i; Datatypes: Yes/No

This optional parameter is used to activate a version check.

The example below illustrates how to use the version check.

Because all write operations automatically lock the table in use, the dbLOCKTABLE would seem unnecessary. Imagine however a transac-tion in which an application wants to inspect data and then only possibly change it, with a guarantee that the data being changed has not been mod-ified by other applications since the read. The solution is to explicitly lock the table before the read operation, thereby ensuring that no other applica-tion makes changes between the read and the possible write.

Refer to “The NAVISION DBMS” for an explantion of table locking.

The following examples illustrate how to use the dbLOCKTABLE func-tion.

Without using the optional parameter VersionCheck:

Figure 4 illustrates the scope of write locks in an AL code module. The figure illustrates both an explicit lock and an automatic lock.

Line (1) in the write transaction explicitly locks table A. If this explicit lock was not set on table A, the DBMS would automatically lock this table when a record is inserted (3). Table B is not locked explicitly, but is locked automatically by the DBMS when a record is inserted (4). Both

To... Enter...

make the system wait until the table is unlocked, if another appli-cation already has locked the table

TRUE or leave blank (Default)

make dbLOCKTABLE terminate with a run time error, if another application already has locked the table

FALSE

To... Enter...

de-activate version check FALSE (or leave blank)

activate version check TRUE

dbLOCKTABLE

Record

Wait

VersionCheck

General comments

For Example...

Page 102: Guide to the Navision Al Dbms

dbLOCKTABLE

98 ALReference Guide

locks are active until the system exits the AL code module (5).

.

Using the optional parameter VersionCheck:

If a data update depends on a preceding reading, and there is relatively long time between the reading and the writing, it might not be suitable to lock a table as normally done during a transaction, as this means that other users will not be able to update the table until your transaction is committed. The solution is to use the VersionCheck parameter, which causes the system to check if a record has been changes, by comparing time-stamps.

Consider the following example:

dbGETREC(Customer, �AAA 1050�); {Reading at 10:00. Time stamp}

. {automatically set to 10:00}

.

dbLOCKTABLE(Customer, TRUE, TRUE); {Starting write transaction}

. {at 10:15}

dbMODIFYREC(Customer); {A run time error will occur}

. {if the time-stamp on}

. {Customer in the data version}

{End write transaction} {used in the transaction, is

different from the time-stamp

made the last time you read

the record before the write

transaction started}

When the VersionCheck parameter is TRUE, dbMODIFYREC will com-pare the time-stamp on the record you modify within a transaction, with the time-stamp made the last time you read the record before the transac-tion started. If these time-stamps are different, the record has been changed in the period from you read and until you locked the table, and a run time error will occur.

.

.{Enter AL code module} dbLOCKTABLE(TableA); (1) dbFINDREC(TableA, ...); (2) . . dbINSERTREC(TableA, ...); (3) . dbINSERTREC(TableB, ...); (4) . . . . .{Exit AL code module} (5)..

Table Locking

Tabl

e A

lock

ed

Tabl

e B

lock

ed

Figure 4. Thescope of write

locks

Page 103: Guide to the Navision Al Dbms

dbMARKEDONLY

AL Reference Guide 99

Causes a special filter to be activated: your view of the table will only include records marked by dbRECMARK.

OK := dbMARKEDONLY(Record [, MarkedOnly])

- Flow: i; Datatypes: Record

A record from the table for which you want to activate the special ‘mark’filter.

- Flow: i; Datatypes: Yes/No

This optional parameter changes the state of the special filter.

- Flow: o; Datatypes: Yes/No

The return value reflects whether the special filter is activated.

The following AL code sample illustrates how to use the dbRECMARK together with dbMARKEDONLY. Assume that initially none of the records are marked.

dbSELECTKEY(Customer."No.");

Customer."No." := �NEW 3500�;

dbFINDREC(Customer, �=�);

dbRECMARK(Customer, TRUE); {Mark a record}

No1 := dbRECCOUNT(Customer);

dbMARKEDONLY(Customer, TRUE);

No2 := dbRECCOUNT(Customer);

MESSAGE(�Number of records before dbMARKEDONLY: %1\� +

�Number of records after dbMARKEDONLY: %2�, No1, No2);

The message box will show:

To... Enter...

Include only marked records TRUE

Include all records. FALSE

If Ok is... It means that...

TRUE The special filter is in use.

FALSE The special filter in not in use.

Number of records before dbMARKEDONLY: 5

Number of records after dbMARKEDONLY: 1

dbMARKEDONLY

Record

MarkedOnly

Ok

For Example...

Page 104: Guide to the Navision Al Dbms

dbMAXRANGE

100 ALReference Guide

Returns the maximum value for a range for a field in a record.

Value := dbMAXRANGE(Record.Field)

- Flow: i; Datatypes: RecordField

The input field. The current filter on Record.Field must be a single range, otherwise a run time error occurs.

- Flow: o; Datatypes: -

A return value containing the maximum value of the range set for Record.Field. The type of value must match the type of Record.Field.

The following AL code samples illustrate how to use the dbMAXRANGE function.

A filter which is a single range:

dbSETFILTER(Customer."No.",'100..200');

Val := dbMAXRANGE(Customer."No.");

MESSAGE(�The maximum value is: %1�, Val);

The message box will show:

A filter which is a single value:

dbSETFILTER(Customer."No.",'100');

Val := dbMAXRANGE(Customer."No.");

MESSAGE(�The maximum value is: %1�, Val);

The message box will show:

A filter which is not a single range:

dbSETFILTER(Customer."No.",'200|300');

Val := dbMAXRANGE(Customer."No.");

This causes a run time error to occur.

The maximum value is: 200

The maximum value is: 100

dbMAXRANGE

Record.Field

Value

For Example...

Page 105: Guide to the Navision Al Dbms

dbMINRANGE

AL Reference Guide 101

Returns the minimum value for a range for a field in a record.

Value := dbMINRANGE(Record.Field)

- Flow: i; Datatypes: RecordField

The input field. The current filter on Record.Field must be a single range, otherwise a run time error occurs.

- Flow: o; Datatypes: String

A return value containing the minimum value of the range set for Record.Field. The type of Value must match the type of Record.Field.

The following AL code samples illustrates how to use the dbMINRANGE function.

A filter which is a single range:

dbSETFILTER(Customer."No.",'100..200');

Val := dbMINRANGE(Customer."No.");

MESSAGE(�The minimum value is: %1�, Val);

The message box will show:

A filter which is single value:

dbSETFILTER(Customer."No.",'100');

Val :=dbMINRANGE(Customer."No.");

MESSAGE(�The minimum value is: %1�, Val);

The message box will show:

A filter which is not a single range:

dbSETFILTER(Customer."No.",'200|300');

Val := dbMINRANGE(Customer."No.");

This causes a run time error to occur.

The minimum value is: 100

The minimum value is: 100

dbMINRANGE

Record.Field

Value

For Example...

Page 106: Guide to the Navision Al Dbms

dbMODIFYALL

102 ALReference Guide

Modifies a field in all records within a specified range in a table.

dbMODIFYALL(Record.Field, Value)

- Flow: i; Datatypes: RecordField

The field to be modified.

Flow: i; Datatypes: -

The value to be assigned to the field Record.Field in all records. The type of Value must match the type of Record.Field.

If no filter is set, the field is modified in all records in the table. Other-wise dbMODIFYALL will only change the fields in the records within the range(s) specified by the filter.

The following AL code samples illustrate how to use the dbMODIFYALL function.

The function of the statement:

dbMODIFYALL(Customer.Group, 2);

equals the following:

IF dbFINDREC(Customer, �-�) THEN

REPEAT

Customer.Group := 2;

dbMODIFYREC(Customer);

UNTIL dbNEXTREC(Customer) = 0;

But the use of dbMODIFYALL is much faster, as only one server access is needed. The second method requires several server accesses.

dbMODIFYALL

Record.Field

Value

General Comments...

For Example...

Page 107: Guide to the Navision Al Dbms

dbMODIFYREC

AL Reference Guide 103

Modifies a record in a table.

[Ok :=] dbMODIFYREC(Record)

- Flow: i; Datatypes: Record

The record to be modified. Record itself does not change.

- Flow: o; Datatypes: Yes/No

If this optional return value is not used, a run-time error occurs if the record does not exist. Using the value, it is possible for the programmer to take care of the error handling. The possible values are: .

The record to be replaced is identified by the primary key fields. The cur-rent key and filters on the record does not affect this operation.

In multi user environments, another application can modify the record in the table in the interval between your reading the record and your attempt to modify it. The NAVISION DBMS automatically detects this, which causes the dbMODIFYREC function to terminate with a run time error.

The following AL code sample illustrates how to use the dbMODI-FYREC function.

Customer."No." := �AAA 1050�;

dbFINDREC(Customer, �=�); {Find customer}

MESSAGE(�The customer no. %1 corresponds to:\� +

�%2�, Customer."No.", Customer.Name);{Display name}

WAITKEYPRESS;

Customer.Name := �Joe Blow�;

dbMODIFYREC(Customer); {Modify customer name}

MESSAGE(�Now customer no. %1 corresponds to:\� +

�%2�, Customer."No.", Customer.Name);{Display modified

name}

When a specific customer has been located, the message box shows:

After the information has been modified, the second message box shows:

If Ok is... It means that...

TRUEThe record was successfully mod-ified

FALSEThe record could not be found in the table

The customer no. AAA 1050 corresponds to:

AAA Furniture Manufacturing

Now customer no. AAA 1050 corresponds to:

Joe Blow

dbMODIFYREC

Record

Ok

General Comments...

For Example...

Page 108: Guide to the Navision Al Dbms

dbNEXTREC

104 ALReference Guide

Steps through a specified number of records to retrieve a record.

ActualSteps := dbNEXTREC(Record [, Steps])

- Flow: io; Datatypes: Record

The record from which the search shall begin. Return the retrieved record.

- Flow: i; Datatypes: Number

Is used to define the direction of the search, according to the following rules:

If Steps is not specified, the next record is found.

- Flow: o; Datatypes: Number

The function returns the number of records traversed which meet the cri-teria of any filters and the current key. This value can be closer to zero than Steps, depending upon the number of records in the table. If the table is empty, zero is returned and Record remains unchanged

dbNEXTREC locates a record positioned a given number of steps for-ward or backward from Record. Movement through the table is governed by the filters and the current key associated with the records. The fields in Record which will be compared with the current key fields, must contain appropriate values before the function is called.

The following AL code sample illustrates how to use the dbNEXTREC function.

Count := 0;

IF dbFINDREC(Customer, �-�) THEN

REPEAT

Count := Count + 1;

UNTIL dbNEXTREC(Customer) = 0;

The above code uses a REPEAT UNTIL loop to count the number of entries in the Customer table. The dbFINDREC function is used to find the first entry in the table. Each time dbNEXTREC is called, it steps one record forward. When dbNEXTREC = 0 there are no more entries in the table and the system exits the loop.

Value of Steps Effect...

> 0Search Steps records forwards in the table.

< 0Search Steps records backwards in the table.

= 0 No effect

dbNEXTREC

Record

Steps

ActualSteps

General Comments..

For Example...

Page 109: Guide to the Navision Al Dbms

dbRECCOUNT

AL Reference Guide 105

Counts the number of records in a table.

Number := dbRECCOUNT(Record)

- Flow: i; Datatypes: Record

A record from the table to be counted.

- Flow: o; Datatypes: Number

The number of records.

The dbRECCOUNT function returns the number of records that meet the conditions of any filters associated to the records. If no filters are set, the function returns the total number of records in the table.

The number of filters applied to the records affects the speed of the dbRECCOUNT function. The operation is fastest when no filters are applied.

The following illustrates how to use the dbCOUNTREC function. The first statement:

Number :=dbRECCOUNT(Customer);

assigns the number of records in the Customer table to the Number vari-able. This statement equals:

Count := 0;

IF dbFINDREC(Customer, �-�) THEN

REPEAT

Count := Count + 1;

UNTIL dbNEXTREC(Customer) = 0;

However, the first example is much faster, as only one command to the DBMS is needed. The second example requires that several command are send to the DBMS.

dbRECCOUNT

Record

Number

General Comments...

For Example...

Page 110: Guide to the Navision Al Dbms

dbRECMARK

106 ALReference Guide

Marks a record.

Ok := dbRECMARK(Record [, Mark])

- Flow: i; Datatypes: Record

The input record.

- Flow: i; Datatypes: Yes/No

- Flow: o; Datatypes: Yes/No

The return value reflects whether Record is marked.

The mark is valid until the execution of the application ends.

The following AL code sample illustrates how to use the dbRECMARK function. Assume that initially no records are maked.

dbSELECTKEY(Customer."No.");

Customer."No." := �NEW 3500�;

dbFINDREC(Customer, �=�);

dbRECMARK(Customer, TRUE); {Mark a record}

dbFINDREC(Customer, �-�); {Find first record}

REPEAT {Iterate through records}

Marked := dbRECMARK(Customer); {Test if marked?}

MESSAGE(�Customer.No.:%1, Marked?: %2�, Customer."No.", Marked);

UNTIL dbNEXTREC(Customer) = 0;

The example illustrates that dbRECMARK both can be used to explicitly mark a record, and to test whether a record is marked or not.

The message boxes will show:

To... Enter...

Mark the record. (Already marked records remains marked).

TRUE

Remove existing mark, if any. FALSE

If Res is... It means that...

TRUE The record is marked.

FALSE The is not marked.

Customer No.: AAA 1050, Marked?: No

Customer No.: DEL 3500, Marked?: No

Customer No.: NEW 3500, Marked?: Yes

Customer No.: PEA 2500, Marked?: No

dbRECMARK

Record

Mark

Ok

For Example...

Page 111: Guide to the Navision Al Dbms

dbRECMARK

AL Reference Guide 107

The next example shows how to used the dbRECMARK together with dbMARKEDONLY. Assume that initially none of the records are marked.

dbSELECTKEY(Customer."No.");

Customer."No." := �NEW 3500�;

dbFINDREC(Customer, �=�);

dbRECMARK(Customer, TRUE); {Mark a record}

No1 := dbRECCOUNT(Customer);

dbMARKEDONLY(Customer, TRUE);

No2 := dbRECCOUNT(Customer);

MESSAGE(�Number of records before dbMARKEDONLY: %1\� +

�Number of records after dbMARKEDONLY: %2�, No1, No2);

The message box will show:

Customer No.: SOP 7500, Marked?: No

Number of records before dbMARKEDONLY: 5

Number of records after dbMARKEDONLY: 1

Page 112: Guide to the Navision Al Dbms

dbRESETTABLE

108 ALReference Guide

Removes all filters (also special filters set by dbMARKEDONLY), and changes the current key to the primary key.

dbRESETTABLE(Record [, GlobalFilters])

- Flow: io; Datatypes: Record

A record from the table to be resat.

- Flow: i; Datatypes: Yes/No

This optional parameter determines whether global filters are to be removed.

Refer to the function dbGLOBALFILTER for additional information about global filters.

The following AL code sample illustrates how to use the dbRESETTA-BLE function.

dbSETFILTER(Customer."No.", �NEW 3500�);

dbSETRANGE(Customer."Salesperson Code", �B. SANDERS�);

dbMARKEDONLY(Customer, TRUE);

Count := dbRECCOUNT(Customer); {Count the marked customers

within a specified range}

dbRESETTABLE(Customer);

Count1 := dbRECCOUNT(Customer); {Count all customers}

MESSAGE(�Before dbRESETTABLE: %1\� +

�After dbRESETTABLE: %2�, Count, Count1);

The message box will show:

The example illustrates that all filters have been removed by the call of dbRESETTABLE.

To... Enter...

Prevent global filters from being removed.

FALSE (Default value).

Remove global filters. TRUE

Before dbRESETTABLE: 0

After dbRESETTABLE: 5

dbRESETTABLE

Record

GlobalFilters

General Comments...

For Example...

Page 113: Guide to the Navision Al Dbms

dbSELECTCOMPANY

AL Reference Guide 109

Redirects references to table data to another company.

[Ok :=] dbSELECTCOMPANY(Record [, CompanyName])

- Flow: i; Datatypes: Record

A record from a table to be accessed in another company.

-Flow: i; Datatypes: String

The name of the company to be accessed. If CompanyName is not speci-fied, the initial company is used.

- Flow: o; Datatypes: Yes/No

If this optional return value is not used, a run-time error occurs if the com-pany does not exist. Using the value, it is possible for the programmer to take care of the error handling. The possible values are:

This function respects the user’s authorization. Thus, a user cannot access data in CompanyName, unless the user already have the necessary autho-rization assigned by a super user.

The dbSELECTCOMPANY function is not affected by dbRESETTA-BLE. The only way to deselect a company, is by a new call to dbSE-LECTCOMPANY.

Global filters always belong to a specific company. If you use dbSE-LECTCOMPANY(Record, 'NewCompany') to select the company named 'NewCompany', any filters assigned to Record will be transferred to Record in the new company; but if any of the filters have status as a glo-bal filter, this status will be removed.

When you return to the initial company, the global filters are automati-cally reestablished for Record. If the filters for Record have been removed, the global filters can be restablished by calling dbRESETTA-BLE (Record,FALSE).

The following AL code sample illustrates how to use the dbSELECT-COMPANY function.

dbSELECTCOMPANY(�G/L Account�,'New Company');

dbGETREC(�G/L Account�,'1000');

dbCALCFIELDS(�G/L Account�.Balance); {Calculates the balance for

account no. 1000 in the Com-

pany named 'New Company'}

dbSELECTCOMPANY(�G/L Entry�,'New Company');

dbSELECTKEY(�G/L Entry�.�No.�,FinanceEntry.Date);

dbSETRANGE(�G/L Entry�.�No.�,'1000');

If Ok is... It means that...

TRUE The company was found.

FALSE The company could not be found.

dbSELECTCOMPANY

Record

CompanyName

Ok

General Comments...

For Example...

Page 114: Guide to the Navision Al Dbms

dbSELECTCOMPANY

110 ALReference Guide

dbSETRANGE(�G/L Entry�.Date,010194D,013194D);

dbSUM(�G/L Entry�.NettAmount); {Sums NettAmount from all G/L

entries on account no. 1000

within the specified range,

for the company 'New Company'}

dbRESETTABLE(�G/L Entry�);

dbFINDREC(�G/L Entry�,'+'); {Finds the largest �No.� in

table G/L Entry in the Company

'New Company'}

dbDELREC(�G/L Entry�); {Deletes this entry in the

company 'New Company'}

The above example illustrates that when dbSELECTCOMPANY has been called, all future references to the “G/L Account” and the “G/L Entry” tables will refer to the table data in the company ‘New Company’.

Page 115: Guide to the Navision Al Dbms

dbSELECTKEY

AL Reference Guide 111

Selects a key for a table.

[Ok :=] dbSELECTKEY(Record.Field [, Record.Field, ...])

- Flow: i; Datatypes: RecordField

One or more fields identifying the key to be selected.

- Flow: o; Datatypes: Yes/No

If this optional return value is not used, a run-time error occurs if the key does not exist. Using the value, it is possible for the programmer to take care of the error handling. The possible values are:

dbSELECTKEY assigns a specified key to a record. The key becomes the current key and is used by dbFINDREC, dbNEXTREC and other func-tions until another another key is selected. Until this function is called, the primary key for the table is used as current key.

Non-active fields are automatically ignored. When searching in the key table, the first occurrence of the specified fields is always selected. This implies that the selected may be more comprehensive than specified. Only active keys are scanned.

Refer to “The NAVISION DBMS” for an explanation about keys.

The following AL code samples show how to use the dbSELECTKEY function.

Without using the return value:

dbSELECTKEY(Customer.Name);

The above statement selects the Name key for the Customer table. If the system cannot find the desired key a run time error occurs.

Using the return value:

By using the return value, a run time error can be avoided, if the system cannot find the desired key.

IF dbSELECTKEY(Customer.Name) THEN

MESSAGE(�The key was successfully selected!�)

ELSE

MESSAGE(�Sorry, the key could not be found...�);

If Ok is... It means that...

TRUEThe key was successfully selected.

FALSE The key does not exist.

Note : To choose from the list of active keys while in the AL editor, press F5 to enter the Symbols survey. Highlight a table variable and press F6 twice.

dbSELECTKEY

Record.Field

Ok

General Comments...

For Example...

Page 116: Guide to the Navision Al Dbms

dbSETCURREC

112 ALReference Guide

Marks a record as current record.

dbSETCURREC(Record)

- Flow: i; Datatypes: Record

The record to be marked as current.

In each object containing AL code, only one record per table can be marked as current record. Attempts to mark two different records from the same table as current in the same object will cause a run time error.

In Window objects, the record selected by the cursor will automatically be marked as current record, when calling sub-objects.

A mark will be valid until the system exits the AL code module in which dbSETCURREC was used.

Please observe that it is not the contents of the record, but the address of the record which is stored as current record. If the contents of the record is changed after dbSETCURREC has been called, then it is possible to get hold of the contents of the record, using dbGETCURREC.

The following explains how to use the dbSETCURREC function.

If this function is used in Entry processing code, and the code calls a report (callREPORT), then it is possible to gain access to the current record using dbGETCURREC.

This is for example used in the NAVISION demo application when con-currently posting and printing an invoice. The following three steps must be accomplished:

1. Call a function which can perform the posting.

2. Call dbSETCURREC(InvoiceHeader).

3. Use callREPORT to call a report to take care of the printing.

In the report, the report element InvoiceHeader must have the option field Current Record set to Yes.

The result is that only one invoice will be printed, corresponding to InvoiceHeader, as set by dbSETCURREC(InvoiceHeader).

dbSETCURREC

Record

General Comments...

For Example...

Page 117: Guide to the Navision Al Dbms

dbSETFILTER

AL Reference Guide 113

Assigns a filter to a specified field.

dbSETFILTER(Record.Field, String [, Value, ...])

- Flow: i; Datatypes: RecordField

The field to be filtered.

- Flow: i; Datatypes: String

The filter expression. A valid expression consists of alphanumeric charac-ters and one or more of the following operators: ‘<‘, ‘>’, ‘?’, ‘&’, ‘|’ and ‘=’. Furthermore replacement fields (%1, %2, ...) can be used to insert values at run time.

- Flow: i; Datatypes: -

Replacement values to be inserted at replacement fields in the filter expression. The type of Value must match the type of Record.Field.

If the function is called with a field for which a filter already exists, this filter will be removed before the new one is set.

Filters can be constructed, using the following operators

The following operators can only be used for date fields :

Read more about filters in “The NAVISION DBMS”.

The following table show examples of filters.

Operator... Explanation...

.. Range

& And

| Or

< Less than

<= Less than or equal to

> Greater than

>= Greater than or equal to

<> Different from

? Forms a part of value

Operator Explanation...

P Current period

Px..Py Period x to y

Y Current year

Example... Explanation...

A..Z range from A to Z

A | G A or G

dbSETFILTER

Record.Field

String

Value

General Comments...

For Example...

Page 118: Guide to the Navision Al Dbms

dbSETFILTER

114 ALReference Guide

The following AL code shows how to use the dbSETFILTER function.

Using a filter with replacement fields:

dbSETFILTER("G/L Account"."No.", �%1..%2|%3�, �100�, �200�, �300�);

Selects all accounts in the range from 100 to 200 and account no. 300

Using a filter entered directly in a string:

The following filter which is entered directly in a string, correspond to the above example.

dbSETFILTER("G/L Account"."No.", �100..200|300�);

Selects all accounts in the range from 100 to 200 and account no. 300.

F.. & ?A/Sfrom F and A/S is included in the field.

<>B all except B

<>'' all not blank

<=200 | >500 all less than or equal to 200 or greater than 500

Example... Explanation...

Page 119: Guide to the Navision Al Dbms

dbSETRANGE

AL Reference Guide 115

Sets a simple filter (a single range or a single value) on a field.

dbSETRANGE(Record.Field [, FromValue] [, ToValue])

- Flow: i; Datatypes: RecordField

The field to be filtered.

- Flow: i; Datatypes: -

The lower limit of the range. The type of FromValue must match Record.Field.

- Flow: i; Datatypes: .

The upper limit of the range. If ToValue is not specified, dbSETRANGE will use the same value as specified for FromValue. The type of ToValue must match Record.Field.

dbSETRANGE provides a quick way to set a simple filter on a field.

If the function is called with a field for which a filter already exists, this filter will be removed before the new one is set.

If none of the optional parameters are specified, dbSETRANGE will remove the filter set for Record.Field (if any).

Read more about filters in “The NAVISION DBMS”.

The following AL code sample illustrates how to use the dbSETRANGE function to specify that you only what to see customers with numbers in the range 100 to 200.

dbSETRANGE(Customer.�No.�, �100�, �200�);

The above statement is a quick way to set the same filter as:

dbSETFILTER(Customer.�No.�, �>=100&<=200�);

dbSETRANGE

Record.Field

FromValue

ToValue

General Comments...

For Example...

Page 120: Guide to the Navision Al Dbms

dbSUM

116 ALReference Guide

Sums specified columns in a table.

dbSUM(Record.Field [, Record.Field, ...])

- Flow: io; Datatypes: RecordField

One or more fields which are defined as sum fields in the current key. All the fields specified must be defined as sum fields in the current key, other-wise a run time error will occur.

dbSUM adds up columns in a table. The function operates only on records which meet the conditions of any filters associated with the record.

Refer to “The NAVISION DBMS” for an explanation about the concept of sum fields.

The following AL code illustrates how to use the dbSUM function.

dbSELECTKEY("Cust. Ledger Entry"."Customer No.","Cust. Ledger Entry".Date);

dbSETRANGE("Cust. Ledger Entry"."Customer No.", �AAA 1050�);

dbSETRANGE("Cust. Ledger Entry".Date, 010194D, 123194D);

dbSUM("Cust. Ledger Entry".Amount);

The first line selects a key. The second and third lines sets filters for the fields “Customer No” and Date in the record “Cust. Ledger Entry” so that the sum is only calculated within the specified range. dbSUM is then used to find the movement in the account 'AAA 1050' for 1994, and the result is placed in the Amount field.

dbSUM

Record.Field

General Comments...

For Example...

Page 121: Guide to the Navision Al Dbms

dbTESTFIELD

AL Reference Guide 117

Tests if the contents of a field matches a value. If not, an error message is displayed.

dbTESTFIELD(Record.Field [, Value])

- Flow: i; Datatypes: RecordField

The field to be tested.

- Flow: i; Datatypes: -

The value to be matched with Record.Field. The type of Value must match the type of Record.Field. If this optional parameter is not speci-fied, the test value is set to 0 or the empty string.

The following AL code samples illustrates how to use the dbTESTFIELD function.

Without using the optional Value:

Customer.�No.� := ��;

dbTESTFIELD(Customer.�No.�)

Returns an error message:

Using the optional value:

Customer.�No.� := �AAA 1050�;

dbTESTFIELD(Customer.�No.�,'1000')

If No. is different from 1000, the following error message will be shown:

An analogy:

The dbTESTFIELD function corresponds to:

IF Record.Field <> Value THEN

dbFIELDERROR(Record.Field);

You must specify No.

in the below Customer

No. must be 1000

in the below Customer

AAA 1050

dbTESTFIELD

Record.Field

Value

For Example...

Page 122: Guide to the Navision Al Dbms

dbTRANSFERFIELDS

118 ALReference Guide

Copies all matching fields in one record to another record, according to the specification in the Field Transfer Table (Design, Tables, Field Trans-fers).

dbTRANSFERFIELDS(FromRecord, ToRecord [, All])

- Flow: i; Datatypes: Record

The record to be copied from.

- Flow: o; Datatypes: Record

The matching field values are assigned to fields in this record.

- Flow: i; Datatypes: Yes/No

This optional parameter determines whether all fields should be copied, or if the Field Transfer Table should be used.

FromRecord and ToRecord may come from two different tables.

The following Al code sample shows how to use the dbTRANSFER-FIELDS function.

dbTRANSFERFIELDS can be used to automatically fill in an Invoice Header, based on a Customer no.

{Assume that the user has entered a Customer no.}

{in �Invoice Header�.�CustomerNo.�}

dbGETREC(Customer, �Invoice Header�.�CustomerNo.�);

{Finds a customer in the Customer table}

dbTRANSFERFIELDS(Customer, �Invoice Header�);

Based on a customer no., a customer is found in the Customer table. The fields in the “Invoice Header” record, is automatically filled in according to the Field Transfer Table.

a. Only fields which exists in both records will be copied, and only if they have the same field type.

To... Enter...

copy all fields, independent of the transfer tablea.

TRUE

copy based on the Field Transfer Table.

FALSE or leave blank (Default)

dbTRANSFERFIELDS

FromRecord

ToRecord

All

General Comments...

General Comments...For Example...

Page 123: Guide to the Navision Al Dbms

DELCHR

AL Reference Guide 119

Deletes one or more characters in a String.

NewString := DELCHR(String [, Where] [, Which])

- Flow: io; data types: String

The input string.

- Flow: i; data types: String

A string used to specify where deletion is to be made. The Where string may contain one or more of the following characters:

- Flow: i; data types: String

A string containing the characters to be deleted. The DELCHR function is case-sensitive.

If Which is not specified, ‘=’ will be used as default.

- Flow: o; data types: String

The resulting string.

This example shows how to use the DELCHR function.

Str := 'Windy Solutions';

Where := '<>';

Which := 'Ws';

NewStr := DELCHR(Str, Where, Which);

MESSAGE('>%1<, is transformed to: >%2<', Str,NewStr);

The two strings are shown in the message-box as:

Where Effect

=

Any character in String which matches a character in Which will be deleted from String. This is the default value.

<Any leading character in String which matches a character in Which will be deleted from String.

>Any trailing character in String which matches a character in Which will be deleted from String.

>Windy Solutions<, is transformed to: >indy Solution<

DELCHR

String

Where

Which

NewString

For Example...

Page 124: Guide to the Navision Al Dbms

DELSTR

120 ALReference Guide

Deletes a sub-string in a String.

NewString := DELSTR(String, Position [, Length])

- Flow: i; data types: String

The input string.

- Flow: i; data types: Number

The position of the first characcter to be deleted. Position must be greater than 0 (zero).

- Flow: i; data types: Number

Specifies the number of characters to be deleted. Must be greater than 0.

If Length is not specified, all characters from Position and to the end of the string will be deleted.

- Flow: o; data types: String

The resulting string.

The following illustrates how to use the DELSTR function.

Str := 'Adjusting Prices - Please wait';

Position := 11; {Remove the word 'Prices' and a blank}

Length := 7;

NewStr := DELSTR(Str, Position, Length);

MESSAGE('The original string:\ >%1<', Str);

MESSAGE('The modified string:\ >%1<', NewStr);

The first message-box above will show the following:

...while the second message-box will show:

Note : If Position exceeds the length of String, DELSTR will return the entire original string.

The original string:

>Adjusting Prices - Please wait<

The modified string:

>Adjusting - Please wait<

DELSTR

String

Position

Length

NewString

For Example...

Page 125: Guide to the Navision Al Dbms

DMY2DATE

AL Reference Guide 121

Returns a date based on Day, Month and Year.

Date := DMY2DATE(Day [, Month] [, Year])

- Flow: i; data types: Number

The number of the day in the month (1..31).

- Flow: i; data types: Number

The number of the month (1..12). If this optional parameter is not used, the system will use the current month as default.

- Flow: i; data types: Number

Ranges from 1980 to 2059. If this optional parameter is not used, the sys-tem will use the current year as default.

- Flow: o; data types: Date

The resulting date.

This AL code sample shows how to use the DMY2DATE function.

Day := 11;

Month := 2;

Year := 1996;

D := DMY2DATE(Day, Month, Year);

MESSAGE('Day no. %1,\� +

'month no.%2, and\' +

�year no. %3 \' +

'corresponds to the date: %4', Day, Month, Year, D);

The message box will show:

Day no. 11

month no. 2, and

the year 1996

corresponds to the date: 02/11/96

DMY2DATE

Day

Month

Year

Date

For Example...

Page 126: Guide to the Navision Al Dbms

DWY2DATE

122 ALReference Guide

Returns a Date based on a WeekDay, a Week and a Year.

Date := DWY2DATE(WeekDay [, Week] [, Year])

- Flow: i; data types: Number

The number of the day in the week (1..7). Monday is No. 1.

- Flow: i; data types: Number

The number of the week. If this optional parameter is not used, the default is the current week.

- Flow: i; data types: Number

Ranges from 1980 to 2059. If this optional parameter is not used, the default is the current year

- Flow: o; data types: Date

The resulting date.

A special situation occurs if the input Week to DWY2DATE is a week which overlaps two years. Depending on the Weekday, the year of the output Date may be different from the input year. This is illustrated by the example below.

The following AL code sample shows how to use the DWY2DATE func-tion. Please note that the input week in this example overlaps two years.

DayOfWeek := 7;

Week := 52;

Year := 1993;

aDate := DWY2DATE(DayOfWeek, Week, Year);

MESSAGE('The %1. day of the week \' +

'in the %2. week\' +

'in the year %3,\' +

'corresponds to the date: %4', DayOfWeek, Week, Year, aDate);

The message box will show:

The example illustrates that the system regards the 7. day of the week in the 52. week in the year as the date 01/02/94.

The 7. day of the week

in the 52. week

in the year 1993,

corresponds to the date: 01/02/94

DWY2DATE

WeekDay

Week

Year

Date

General Comments...

For Example...

Page 127: Guide to the Navision Al Dbms

ERROR

AL Reference Guide 123

Prints an error message on the screen and ends the execution of the AL code.

ERROR(String [, Value1, ...])

-Flow: i; data types: String

A string containing text to be shown in the error box. The special charac-ter '\' divides String into sub-strings, and causes the printing to start on a new line.

In order to insert variable values in the string, '%'- or '#'-fields can be inserted at the position(s) where the value(s) are to be substituted.

The size of the resulting error box is determined as follows: the width cor-responds to the longest sub-string in String, and the height corresponds to the number of sub-strings (lines). The system truncates any sub-string longer than 64 characters.

- Flow: i; data types: see text below

Any variable or expression to be inserted in String. A maximum of 10 values can be inserted.

Values substituted in a '#'-type field will be truncated to a length corre-sponding to the number of '#'-characters, whereas values substituted in a '%'-type field will be printed full length.

The following AL code sample illustrates how to use the ERROR func-tion.

AccountNo := 1230;

{The execution will be halted when the error statement is executed,}

{and the following statements will never be executed.}

ERROR('Finance Account #1####\' +

'must not be blocked', AccountNo);

MESSAGE('Dummy message!'); {This line is never executed}

The ERROR box will show:

... the ERROR statement causes the execution of the AL code to be halted, that is, the MESSAGE function will never be executed.

Finance Account 1230

must not be blocked

ERROR

String

Value1,...

For Example...

Page 128: Guide to the Navision Al Dbms

EVALUATE

124 ALReference Guide

Evaluates a string representation of a value into its normal representation. The result is assigned to a Variable.

[Ok :=] EVALUATE(Variable, String)

- Flow: o; data types: Yes/No, Number, Date, Time, String

Any type of variable. The value of the evaluated string is assigned to the variable.

- Flow: i; data types: String

A string containing a value of any simple AL data type.

- Flow: o; data types: Yes/No

A return code which reflects whether an error occurred during the evalua-tion of the string.

If this optional return value is not used, an error during the evaluation of the string will cause a run-time error. Otherwise it is assumed that the pro-grammer takes care of the error-handling.

The following AL code sample illustrates the behavior of the EVALU-ATE function when called with variables of three different types.

Value := '010196';

Ok1 := EVALUATE(VarInteger, Value);

Ok2 := EVALUATE(VarDate, Value);

Ok3 := EVALUATE(VarYesNo, Value);

MESSAGE('VarInteger = #1######, and the return code is: %2\' +

'VarDate = #3######, and the return code is: %4\'+

'VarYesNo = #5######, and the return code is: %6', VarIn-

teger, Ok1, VarDate, Ok2,

VarYesNo, Ok3);

The message box will show:

The example illustrates that Value ('010196') can be interpreted both as an integer- and a date-expression, while it can not be interpreted as an Yes/No-expression. This causes an error which is reflected through the value of the return code Ok3 (=FALSE).

Ok Indicates that...

TRUENo errors occurred during the evaluation of the string. The value has been assigned to Variable.

FALSEErrors occurred during the evaluation of the string. The original value of Variable has not been modified.

VarInteger = 10196 , and the return code is: Yes

VarDate = 01/01/96, and the return code is: Yes

VarYesNo = No , and the return code is: No

EVALUATE

Variable

String

Ok

For Example...

Page 129: Guide to the Navision Al Dbms

FORMAT

AL Reference Guide 125

Formats an input Value, and returns the result as a String.

String := FORMAT(Value [, Length] [, FormatNo])

- Flow: i; data types: see text below

Value denotes an AL variable (expression) of any simple AL data type.

- Flow: i; data types: Number

This optional argument is an integer which determines the length of the resulting string. Observe the following rules:

- Flow: i; data types: Number

This optional argument determines the format to be used during the for-matting process. There are three or more formats for each simple AL data type:

In the following four subsections we describe all possible formats for any simple AL data type. The subsections describe formats for:

1. Numbers : Yes/No, Option, Integer, Long Integer, Decimal No.

2. Dates .

3. Times .

4. Strings : Text and Code.

Note : If the formatting results in a value larger than MAXSTRLEN(String) a run-time error occurs.

Value of Length Specifies that...

Length = 0 The entire Value will be output (Default).

Length > 0

String will be exactly Length characters. If the length of Value is less than Length characters, spaces will be padded either as leading or trailing characters, depend-ing on which FormatNo you use.If Value is a Number which exceeds Length digits, the output string will contain Length asterisks. Any other non-Number Value which exceeds Length characters, will be truncated.

Length < 0

String will have the maximum length of -Length characters. If the length of Value is less than -Length characters, the length of String will be set to the length of ValueIf Value is a Number which exceeds -Length digits, the output string will contain -Length asterisks. Any other non-Number Value which exceeds -Length characters, will be truncated.

Format No. Explanation

0 Standard Display Format. Default for all data types

1 Standard Display Format 2 (Edit)

2 AL Code Constant Format

3, 4, ... Other formats

FORMAT

Value

Length

FormatNo

Page 130: Guide to the Navision Al Dbms

FORMAT

126 ALReference Guide

Formatting of NumbersTable 28 shows match characters for Numbers formats. These match char-acters are used (in column 3) in table 29, which shows the possible for-mats for Numbers.

Table 28: Match Characters in Number Formats

Sign Explanation...

Yes/No Display a Yes with the value 1; display a No with the value 0.

tDisplay the corresponding text from the option set defined for the field.

-Display a minus with any negative number; display nothing with any positive number.

-/_ Display a minus with any negative number; display a space with any positive number.

#Display the integer part of the number without thou-sand separators.

#,### Display the integer part of the number with thousand separators.

.d Display the fractional part of the number, if any, with a leading period.

Table 29: Number Formats

Data type FormatNo Match Character Alignment Example

Yes/No 0, 1 Yes/No Left �Yes �

�No �

2 # Left �0 �

�1 �

Option 0, 1 t Left �Option1 �

�Option2 �

2 # Left �0 �

�1 �

Integer 0, 2 -# Right � 12345�

� -12345�

1 -# Left �12345 �

�-12345 �

Long Integer 0 -#,### Right � 12,345�

� -12,345�

1 -# Left �12345 �

�-12345 �

2 -# Right � 12345�

� -12345�

Page 131: Guide to the Navision Al Dbms

FORMAT

AL Reference Guide 127

Formatting of DatesTable 30 shows match characters for Dates. These match characters are used (in column 3) in table 31, which shows the possible formats for Dates

Decimal No. 0 -#,###.d Right � 12,345.12�

� -12,345.12�

1 -#.d Left �12345.12 �

�-12345.12 �

2 -#.d Right � 12345.12�

� -12345.12�

3 #,###.d-/_ Right � 12,345.12 �

� 12,345.12-�

4 #.d-/_ Right � 12345.12 �

� 12345.12-�

Table 30: Match Characters in Date Formats

Sign Explanation

dDisplay the day as a number without a leading zero (1-31).

dd Display the day as a number with a leading zero (01-31).

mmDisplay the month as a number with a leading zero (01-12).

mmmmDisplay the month as a full month name (January-December).

yyDisplay the year as a two-digit number (80-99,00-59).

yyyy Display the year as a four-digit number (1980-2059).

C Display an uppercase C with any closing date.

D/C Display an uppercase D with any normal date; dis-play an uppercase C with any closing date.

Table 29: Number Formats

Data type FormatNo Match Character Alignment Example

Page 132: Guide to the Navision Al Dbms

FORMAT

128 ALReference Guide

Formatting of TimesTable 32 shows match characters for Times. These match characters are used (in column 3) in table 33, which shows the possible formats for Times.

Table 31: Date Formats

Data type Format No. Match character Alignment Example

Date 0 Cmm/dd/yy Right � 06/01/94�

1 Cmm/dd/yy Left �06/01/94 �

2 mmddyyD/C Right � 060194D�

3 Cyy/mm/dd Right � 94/06/01�

4 mmmm Cd, yyyy Right � June 1, 1994�

5 Cmmddyy Right � 060194�

6 Cyymmdd Right � 940601�

Table 32: Match Characters for Time Formats

Sign Explanation

hDisplay the 12-clock hour as a number without lead-ing zeros (0-11).

hhDisplay the 12-clock hour as a number with a leading space (_0-11).

hh24 Display the 24-clock hour as a number with leading zeros (00-23).

mmDisplay the minute as a number with leading zeros (00-59).

ssDisplay the second as a number with leading zeros (00-59).

.sDisplay the fractional part of second, if any, with a leading period.

AM/PMDisplay an uppercase AM with any hour before noon; display an uppercase PM with any hour between noon and 11:59 PM.

Table 33: Time Formats

Data type Format No. Match character Alignment Example

Time 0 hh:mm:ss.s AM/PM Left � 3:04:05.06 PM �

1 h:mm:ss.s AM/PM Left �3:04:05.06 PM �

2 hh24mmss.sT Left �15:04:05.06T �

Page 133: Guide to the Navision Al Dbms

FORMAT

AL Reference Guide 129

Formatting of StringsTable 34 shows match characters for Strings. These match characters are used (in column 3) in table 35, which shows the possible formats for Strings.

-Flow: o; data types: String

A string containing the formatted output.

This example shows how to use the FORMAT function.

DecNum := -123456.78;

OutStr := FORMAT(DecNum, 15, 3);

MESSAGE('The formatted value: >%1<', OutStr);

The message box will show::

Table 34: Match Characters for String Formats

Sign Explanation

t Display as text.

Table 35: String Formats

Data type Format No. Match character Alignment Example

Text 0, 1, 2 t Left �ABC �

Code 0, 2 t Left �ABC �

Right � 100�

1 t Left �ABC �

�100 �

The formatted value: > 123,456.78-<

String

For Example...

Page 134: Guide to the Navision Al Dbms

INCSTR

130 ALReference Guide

Increments a positive number, or decrements a negative number inside String by 1 (one).

NewString := INCSTR(String)

-Flow: i; data types: String

The input string.

- Flow: o; data types: String

The output string.

Notice that when the input string contains a number like 99 (which is increased to 100), the length of the output string will be: LEN(String) + 1.

The following AL code sample illustrates the properties of the INCSTR function.

Account := 'Account no. 99 does not balance';

NegAccount := 'Account no. 2342 shows a total of -452 $';

MyAccount := 'My bank account shows a total of 0 $';

MESSAGE('The test-strings before INCSTR is called:\' +

'%1\' +

'%2\' +

'%3\', Account, NegAccount, MyAccount);

ResAccou := INCSTR(Account);

ResNegAc := INCSTR(NegAccount);

ResMyAcc := INCSTR(MyAccount);

MESSAGE('The test-strings when INCSTR has been called:\' +

'%1\' +

'%2\' +

'%3', ResAccou, ResNegAc, ResMyAcc);

The first message box will show:

Note : If the string contains more than one number, only the number closest to the end of the string will be changed. Example: ‘A10B20’ is changed to ‘A10B21’

Note : The number 0 (zero) is considered as a positive num-ber, that is, it is increased by 1 (one). Example: ‘A0’ is changed to ‘A1’.

The test-strings before INCSTR is called:

Account no. 99 does not balance.

Account no. 2342 shows a total of -452 $

My bank account shows a total of 0 $

INCSTR

String

NewString

General Comments

For Example...

Page 135: Guide to the Navision Al Dbms

INCSTR

AL Reference Guide 131

... while the second message box will show:

The example shows that if the string contains more than one number then only the last number will be changed. Furthermore it is seen, that positive numbers (and zero) are increased, while negative numbers are decreased.

The test-strings when INCSTR has been called:

Account no. 100 does not balance.

Account no. 2342 shows a total of -453 $

My bank account shows a total of 1 $

Page 136: Guide to the Navision Al Dbms

INSSTR

132 ALReference Guide

Inserts a SubString in String.

NewString := INSSTR(String, SubString, Position)

- Flow: i; data types: String

The main input string.

- Flow: i; data types: String.

A (sub-)string to be inserted in String

- Flow: i; data types: Number

This optional argument determines the position where SubString will be inserted in String. Position must be greater than or equal to 1.

- Flow: o; data types: String

The resulting string.

The following AL code sample illustrates how to insert one string into another.

Str := 'Press ENTER to continue';

SubString := 'or ESC ';

MESSAGE('The test-string before INSSTR is called:\' +

'>%1<', Str);

NewStr := INSSTR(Str, SubString, 12);

MESSAGE('The resulting string after INSSTR has been called:\' +

'>%1<', NewStr);

The first message-box will show:

...while the second message box will show the following:

Note : If Position > STRLEN(String) then NewString will contain a result which is a concatenation of String and SubString.

The test-string before INSSTR is called:

>Press ENTER to continue<

The resulting string after INSSTR has been called:

>Press ENTER or ESC to continue<

INSSTR

String

SubString

Position

NewString

For Example...

Page 137: Guide to the Navision Al Dbms

LOWERCASE

AL Reference Guide 133

Converts all letters in String to lowercase.

NewString := LOWERCASE(String)

- Flow: i; data types: String

The string to be converted. Only letters in the range A..Z (and special national characters) are affected.

- Flow: o; data types: String

The converted output string.

The following AL code sample illustrates how to use the LOWERCASE function.

Str := 'The Entries are Sorted by Name';

MESSAGE('The test-string before LOWERCASE is called:\' +

'>%1<', Str);

Lower := LOWERCASE(Str);

MESSAGE('The resulting string when LOWERCASE has been called:\' +

'>%1<', Lower);

The first message box will show:

...while the second message box will show:

The test-string before LOWERCASE is called:

>The Entries are Sorted by Name<

The resulting string when LOWERCASE has been called:

>the entries are sorted by name<

LOWERCASE

String

NewString

For Example...

Page 138: Guide to the Navision Al Dbms

MAXSTRLEN

134 ALReference Guide

Returns the maximum length, that is the defined length, for a String vari-able.

Length := MAXSTRLEN(String)

- Flow: i; data types: String

The input string variable .

- Flow: o; data types: Number

The maximum length of the input string variable.

In this example we assume that City has been defined as a Text type vari-able, with the maximum length 30.

City := 'Atlanta';

MaxLength :=MAXSTRLEN(City);

Length := STRLEN(City);

MESSAGE('The MAXSTRLEN function returns: %1,\' +

'while the STRLEN function returns: %2',MaxLength, Length);

The message box will show:

The MAXSTRLEN function returns: 30

while the STRLEN function returns: 7

MAXSTRLEN

String

Length

For Example...

Page 139: Guide to the Navision Al Dbms

MESSAGE

AL Reference Guide 135

Displays a text string in a message box.

MESSAGE(String [, Value1, ...])

- Flow: i; data types: String

A string containing text to be shown in the message box. The special character '\' divides String into sub-strings, and causes the printing to start on a new line.

In order to insert variable values in the string, '%'- or '#'-fields can be inserted at the position(s) where the value(s) are to be substituted.

The size of the resulting message box is determined as follows: the width corresponds to the longest sub-string in String, and the height corresponds to the number of sub-strings (lines). The system truncates any sub-string longer than 64 characters.

- Flow: i; data types: see text below

Any type of AL variable containing a value to be inserted in the text in String. A maximum of 10 values can be inserted.

Values substituted in a '#'-type field will be truncated to a length corre-sponding to the number of '#'-characters, whereas values substituted in a '%'-type field will be printed full length.

Observe the following:

• When the system executes a message statement in the AL code it will not display the message box immediately, but wait until the execution of the AL code is finished or until the system temporarily stops to wait for user interaction.

• Only a limited amount of messages can be held in memory. The exact number of messages depends on the sizes of the individual messages. The execution of the code will be interrupted if the total size of the messages exceeds the available memory.

The following illustrates how to use the MESSAGE function.

Value := 12345.678;

{The backslash is used as 'newline' character.}

{Strings can be concatenated, using the + operator.}

{Variable values can be inserted in the text by using % and #

fields.}

MESSAGE('The message box can be used to\' +

'display text and numbers:\' +

'Free format:\' +

'>%1<\' +

'Two different fixed formats:\' +

'>#2#############<\' +

'>#3###<', Value, Value, Value);

MESSAGE

String

Value1, ...

General Comments...

For Example...

Page 140: Guide to the Navision Al Dbms

MESSAGE

136 ALReference Guide

The message box will show:

Note the way the fixed format truncates the number in the last line above.

The message box can be used to

display text and numbers:

Free format:

>12,345.678<

Two different fixed formats:

>12,345.678 <

>12,34<

Page 141: Guide to the Navision Al Dbms

NORMALDATE

AL Reference Guide 137

Returns the normal date (not closing) for the argument Date.

NewDate := NORMALDATE(Date)

- Flow: i; data types: Date

The input date which can be either a closing date or a normal date. If the value of Date is set to the undefined date (0D), a run time error will occur.

The figure below illustrates how the system sorts the closing dates between the normal dates for an arbitrary month..

- Flow: o; data types: Date

The resulting normal date.

The following AL code samples illustrates how to use the NORMAL-DATE function. In the first example a normal date is given as input, and in the second example a closing date is given as input.

A normal date as input.

OldDate := 040494D;

NorDate := NORMALDATE(OldDate);

MESSAGE('The normal date for %1 is %2�, OldDate, NorDate);

The message box will show:

A closing date as input.

OldDate := CLOSINGDATE(040494D);

NorDate := NORMALDATE(OldDate);

MESSAGE(�The normal date for %1 is %2�,OldDate, NorDate);

The message box will show:

Note : All dates have a corresponding closing date. A closing date is regarded by the system as a period following the given date, but before the next normal date, thus closing dates are sorted immediately after the corresponding normal date, but before the next normal date.

If Date is a... Then NewDate will be a...

Normal date Normal date

Closing date Normal date

The normal date for 04/04/94 is 04/04/94

The normal date for C04/04/94 is 04/04/94

NORMALDATE

Date

April 1994

040194D

xxxxxxC: Closing date

...040194C 040294D 040294C 040394D 040394C

xxxxxxD: Normal date

NewDate

For Example

Page 142: Guide to the Navision Al Dbms

OPENWINDOW

138 ALReference Guide

Opens a dialog window on the screen

OPENWINDOW(String [, Line] [, Pos])

- Flow: i; data types: String

A string containing text to be shown in the window. The special character '\' divides String into sub-strings, and causes the printing to start on a new line. The size of the resulting window is determined as follows: the width corresponds to the longest sub-string in String, and the height corresponds to the number of sub-strings (lines).

In order to insert variable values in the string, '#'-fields can be inserted at the positions where the values are to be substituted.

Values substituted in a '#'-type field will be truncated to a length corre-sponding to the number of '#'-characters.

Values can be updated by UPDATEWINDOW, or edited by the user, by using WINDOWINPUT.

- Flow: i; data types: Number

These optional parameters are used to specify the position of the upper left corner of the window. Line and Pos must be greater than or equal to 1. If Line and Pos are not specified the window will be centered at the mid-dle of the screen.

• Each object (function-, report-, ...) can only have one dialog window open at a time. The system will automatically close an existing dialog window before it opens a new dialog window.

• The system will also close the dialog window automatically when an object is terminated.

This example shows how to use the OPENWINDOW function.

AccountInfo := 'Account no. #1######,\' +

'shows a total of #2###### $';

AccNo := 5634;

TotSum := 1000;

OPENWINDOW(AccountInfo, 1, 1); {Upper left corner}

{Opens a window with '#'-fields for Account no. and Total}

UPDATEWINDOW(1, AccNo); {Fill in field no. 1}

UPDATEWINDOW(2, TotSum); {Fill in field no. 2}

WAITKEYPRESS();

CLOSEWINDOW()

The system will open the dialog window and display the following text:

This shows that the values of the variables AccNo and TotSum has been inserted in the '#'-fields.

Account no. 5634

shows a total of 1000 $

OPENWINDOW

String

Line, Pos

General Comments...

For Example...

Page 143: Guide to the Navision Al Dbms

POWER

AL Reference Guide 139

Calculates NumberPower, or in other words, the Powerth power of Num-ber.

NewNumber := POWER(Number, Power)

- Flow: i; data types: Number

Number denotes the base in the exponential function.

-Flow: i; data types: Number

Power denotes the exponent in the exponential function.

- Flow: o; Domains; Decimal No.

The resulting value: NumberPower.

First we will present some typical uses of the POWER function, and sec-ond we will show an AL code saple illustrting how to use the POWER function.

Compound Amount

If a principal P is deposited at interest rate r (in decimals) compounded annually, then at the end of n years the accummulated amount is:

Example: A man deposits $2800 in a bank which pays 5% compounded quarterly. What will the deposit amount to in 8 years?

Answer: There are n = 8x4 = 32 payment periods at interest rate r = 0.05/4 = 0.0125 per period. Then the amount is:

A = $2800(1 + 0.0125)32 =$2800(1.4881) = $4166.68

The Amount of an Annuity

If a principal P is deposited at the end of each year at interest rate r (in decimals) compounded annually, then at the end of n years the accumu-lated amount is:

This is often called an annuity.

Example: An investor has an annuity in which a payment of $500 is made at the end of each year. If interest is 4% compounded annually, what is the amount of the annuity after 20 years?

Answer: Here r = 0.04, n = 20 and the amount will be:

A = $500((1 + 0.04)20 - 1)/0.04 = $14,889.05

POWER

Number

Power

NewNumber

For Example...

A P 1 r+( ) n=

A P 1 r+( ) n 1–r

------------------------------=

Page 144: Guide to the Navision Al Dbms

POWER

140 ALReference Guide

An AL Code Sample

Number1 := 2; Power1 := 8;

Number2 := 100; Power2 := 0;

Number3 := 5; Power3 := -0.5;

Res1 := POWER(Number1, Power1);

Res2 := POWER(Number2, Power2);

Res3 := POWER(Number3, Power3);

MESSAGE('%1 raised to the power of %2 = %3', Number1, Power1, Res1);

MESSAGE('%1 raised to the power of %2 = %3', Number2, Power2, Res2);

MESSAGE('%1 raised to the power of %2 = %3', Number3, Power3, Res3);

The message boxes will show:

The last message box shows that raising a number to the power of -0.5 corresponds to the squareroot of the number.

2 raised to the power of 8 = 256

100 raised to the power 0 = 1

5 raised to the power of -0.5 = 0.44721359549994

Page 145: Guide to the Navision Al Dbms

ROUND

AL Reference Guide 141

Rounds off the value of a Number variable.

NewNumber:= ROUND(Number [, Precision] [, Direction])

- Flow: i; data types: Decimal No.

The input value to be rounded off.

- Flow: i; data types: Decimal No.

This optional parameter determines the precision used when rounding off. The default value is 0.01 for the US version. (In some european countries other default values may be used).

- Flow: i; data types: String

This optional parameter determines how Number is rounded off. The valid values are one of the following three strings:

- Flow: o; data types: Decimal No.

The rounded output value.

The following example shows how to use the ROUND function.

DN := 1234.56789;

Larger := �>�;

Precision := 0.001;

Res := ROUND(DN, Precision, Larger);

MESSAGE(�ROUND(%1, %2, �%3�) returns %4�,DN, Precision, Larger,Res);

The message box will show:

The table below provides additional ROUND examples:

Value of Direction Causes the function to...

'='round off to the nearest value. (Default value)

'>' round up.

'<' round down.

ROUND(1,234.56789, 0.001, �>�) returns 1,234.568

ROUND

Number

Precision

Direction

NewNumber

For Example...

Page 146: Guide to the Navision Al Dbms

ROUND

142 ALReference Guide

Number Precision Direction NewNumber

100 = 1200

0.1 = 1234.6

1234.56789 0.001 = 1234.568

0.001 < 1234.567

0.001 > 1234.568

100 = -1200

0.1 = -1234.6

-1234.56789 0.001 = -1234.568

0.001 < -1234.567

0.001 > -1234.568

Page 147: Guide to the Navision Al Dbms

SELECTSTR

AL Reference Guide 143

Retrieves a sub-string from a comma separated string.

NewString := SELECTSTR(Number, CommaString)

- Flow: i; data types: Number

A number determining the sub-string to be retrieved. The sub-strings in the comma separated string are enumerated as 1, 2, 3, ...

- Flow: i; data types: String

A string containing sub-strings separated by commas.

- Flow: o; data types: String

The sub-string retrieved from CommaString.

The following AL code sample shows how to use the SELECTSTR func-tion.

CommaStr := 'This,is a comma,separated,string';

SubStr1 := SELECTSTR(2, CommaStr); {Pick out the 2nd substring}

SubStr2 := SELECTSTR(4, CommaStr); {Pick out the 4th substring}

MESSAGE('The two calls to SELECTSTR returns:\' +

'>%1<\' +

'>%2<', SubStr1, SubStr2);

The message box will show the following:

Note : If Number is greater than the number of sub-strings, a run-time error will occur.

The two calls to SELECTSTR returns:

>is a comma<

>string<

SELECTSTR

Number

CommaString

NewString

For Example...

Page 148: Guide to the Navision Al Dbms

SERIALNO

144 ALReference Guide

Returns a string, which contain the serial-number for the licence file for your program.

String := SERIALNO()

- Flow: o; data types: String

An output string describing the serial number.

The following AL code sample shows how to use the SERIALNO func-tion.

Sn := SERIALNUMBER();

MESSAGE('The serial number for this\' +

'software package, is: %1', Sn);

The serial number is of course dependent of your software package. The serial number shown in the message box is just an example::

The serial number for this

software package, is: 1-N3001234

SERIALNO

String

For Example...

Page 149: Guide to the Navision Al Dbms

SETSTRLEN

AL Reference Guide 145

Changes the length of a String to a specific Length, either by truncating it, or by concatenating FillerCharacters at the end.

NewString := SETSTRLEN(String, Length[, FillerCharacter])

- Flow: i; data types: String

The input string.

-Flow: i; data types: Number

A number describing the desired length of the output string.

If Length is less than STRLEN(String), the string is truncated. Otherwise it is expanded with filler characters.

- Flow: i; data types: String

This is a string of the length 1. The character in this string is used to 'fill out' empty space at the end of the output string.

If not specified, blanks are used as default.

- Flow: i; data types: String

The output string. The length of NewString is Length characters.

The following AL code sample illustrates how to use the SETSTRLEN function.

Str1 := '13 characters';

Str2 := 'Four';

Len1 := STRLEN(Str1);

Len2 := STRLEN(Str2);

MESSAGE('Before SETSTRLEN has been called:\' +

' >%1<, has the length %2\' +

' >%3<, has the length %4\', Str1, Len1, Str2, Len2);

Str1 := SETSTRLEN(Str1, 5); {Truncate the length to 5}

Str2 := SETSTRLEN(Str2, 15, 'w');{Concatenate w's until length = 15}

Len1 := STRLEN(Str1);

Len2 := STRLEN(Str2);

MESSAGE('After SETSTRLEN has been called:\' +

' >%1<, has the length %2\' +

' >%3<, has th length %4\', Str1, Len1, Str2, Len2);

The first message box will show::

Note : If the maximum (defined) length of the NewString is less than Length, a run-time error will occur.

Before SETSTRLEN has been called:

>13 characters<, has the length 13

>Four<, has the length 4

SETSTRLEN

String

Length

FillerCharacter

NewString

For Example...

Page 150: Guide to the Navision Al Dbms

SETSTRLEN

146 ALReference Guide

...while the second message box will show:

After SETSTRLEN has been called:

>13 ch<, has the length 5

>Fourwwwwwwwwwww<, has the length 15

Page 151: Guide to the Navision Al Dbms

STRCHECKSUM

AL Reference Guide 147

Calculates a checksum for a string containing a number.

CheckNumber:=STRCHECKSUM(String [, WeightString] [, Modulus])

- Flow: i; data types: String

The input string.

- Flow: i; data types: String

A string containing numbers to be used as weights when calculating the checksum. The default value is a string containing STRLEN(String) ‘1’-characters.

- Flow: i; data types: Number

A number to be used in the checksum formula (see below).

The default value is 10.

- Flow: o; data types: Number

The checksum, which is calculated according to the following formula.

where n = STRLEN(String).

The following AL code sample shows how to use the STRCHECKSUM function.

Calculating a checksum:

StrNumber := '4378';

Weight := '1234';

Modulus := 7;

CheckSum := STRCHECKSUM(StrNumber, Weight, Modulus);

MESSAGE('The number: %1\' +

'has the checksum: %2', StrNumber, CheckSum);

The STRCHECKSUM('4378','1234', 7) returns:

Note : Only the numeric characters '0'...'9' are allowed in this string. Using other characters will cause a run time error.

Note : Only the numeric characters '0'...'9' are allowed in this string. Using other characters will cause a run time error.

Note : If String is longer than WeightString, then a string containing STRLEN(String) - STRLEN(WeightString) ‘1’-characters will be concatenated to the end of WeightString. If WeightString is longer than String a run time error will occur.

STRCHECKSUM

String

WeightString

Modulus

CheckNumber

Modulus Str ing i[ ] WeightStr ing i[ ]×1

n

MOD Modulus–

MOD Modulus

For Example...

Page 152: Guide to the Navision Al Dbms

STRCHECKSUM

148 ALReference Guide

(7 - (4x1 + 3x2 + 7x3 + 8x4) MOD 7) MOD 7 = 0

...therefore the message box will show:

Calculating a modulus 10 checksum for bar code:

The STRCHECKSUM function can be used to calculate checksums for 13 and 8 digit EAN (European Article Number) and EAN compatible bar codes such as UPC (Universal Product Code) or JAN (Japanese Article Number).

An 13 digit EAN code has the following format:

Method:

1. The 12 digits in position 13 to 2 are used to calculate the checksum at position 1.

2. Starting from position 2 all values at even positions are summed. The result is multiplied by three. We call this value Even.

3. Starting from position 3 all values at odd positions are summed. We call this value Odd.

4. Total = Even + Odd.

5. The modulus 10 checksum is then: (10 - Total MOD 10) MOD 10.

The following shows how to use STRCHECKSUM to calculate this result.

StrNumber := �577622135746�;

Weight := �131313131313�;

CheckSum := STRCHECKSUM(StrNumber, Weight);

MESSAGE(�The EAN code: %1\� +

�has the checksum: %2�, StrNumber, CheckSum);

The message box will show:

The number: 4378

has the checksum: 0

The EAN code: 577622135746

has the checksum: 3

Position: 13 12 11 10 9 8 7 6 5 4 3 2 1

5 7 7 6 2 2 1 3 5 7 4 6 3

Country code Checksum

Page 153: Guide to the Navision Al Dbms

STRLEN

AL Reference Guide 149

Returns the length of the input string.

Length := STRLEN(String)

- Flow: i; Data types: String

The input string.

- Flow: o; data types: Number

The length of String.

The difference between the STRLEN and MAXSTRLEN functions is that the first reflects the actual number of characters in the input string, while the latter reflects the defined maximum length for the input string. Refer to the example below.

The following AL code sample illustrates the difference between the STRLEN and the MAXSTRLEN functions. We assume that the variable City has been defined with the maximum length 30.

City := 'Atlanta';

MaxLength :=MAXSTRLEN(City);

Length := STRLEN(City);

MESSAGE('The MAXSTRLEN function returns: %1,\' +

'while the STRLEN function returns: %2',MaxLength, Length);

The message box will show:

This illustrates that the MAXLENGTH function returns the maximum possible length according to the definition of the string variable, while STRLEN returns the actual length of the text.

The MAXSTRLEN function returns: 30

while the STRLEN function returns: 7

STRLEN

String

Length

General Comments...

For Example...

Page 154: Guide to the Navision Al Dbms

STRMENU

150 ALReference Guide

Creates a menu box. The menu box is placed at the middle of the screen.

OptionNo := STRMENU(OptionString [, DefaultNo])

- Flow: i; Data types: String

A comma separated string. Each sub-string in OptionString denotes an option in the menu box.

- Flow: i; data types: Number

This optional parameter determines a default option, by highlighting one of the options in the menu box. The options in the menu box are enum-merated 1 , 2 , 3...

If DefaultNo is not specified, the default no. is 1 (one).

- Flow: o; data types: Number

The selected menu option. If the user used ESC to quit the menu box, the value 0 (zero) will be returned.

The following AL code sample illustrateshow to use the STRMENU function.

Options := 'Save,Delete,Exit to OS,Find ...';

Selected := STRMENU(Options, 3); {The 2nd paramenter sets}

{the default to option no. 3}

MESSAGE('You selected option no.: %1', Selected);

A menu box with the following options will be shown:

...and the cursor will be placed on option no. 3 ('Exit to OS'). The selected option will be stored in the variable Selected, and shown by the message box as, for example:

Save

Delete

Find ...

You selected option no.: 2

STRMENU

OptionString

DefaultNo

OptionNo

For Example...

Exit To OS

Page 155: Guide to the Navision Al Dbms

STRPOS

AL Reference Guide 151

Searches for a SubString in a String.

Position := STRPOS(String, SubString)

- Flow: i; data types: String

The string to be searched in.

- Flow: i; data types: String

The string to be searched for.

- Flow: o; data types: Number

The position of SubString in String if SubString was found. If the search fails, the value 0 will be returned.

The STRPOS function only returns the position of the first occurrence of the sub-string.

The following AL code sample illustrates how to use the STRPOS func-tion.

String := 'ABC abc abc xy';

SubStr := 'abc';

Pos := STRPOS(String, SubStr);

MESSAGE('The search for the substring: >%1<\' +

'in the string: >%2<,\' +

'returns the position: %3', SubStr, String, Pos);

{The STRPOS function is case sensitive. Furthermore it only}

{returns the position of the first occurrence of the substring.}

The message box will show::

Note : The STRPOS function is case-sensitive.

The search for the substring: >abc<

in the string: >ABC abc abc xy<

returns the position: 5

STRPOS

String

SubString

Position

General Comments...

For Example...

Page 156: Guide to the Navision Al Dbms

STRSUBSTNO

152 ALReference Guide

Replaces %1, %2,... and #1, #2, ... fields in a String with the value(s) given as optional parameter(s).

NewString := STRSUBSTNO(String [,Value1, ...])

- Flow: i; data types: String

A string containing '#' and/or '%' fields.

The % fields are replaced by the values in full lengths, while # fields are replaced by the values truncated to the length of the # field

- Flow: i; data types: -

One or more values (expressions) to be inserted in String. The value(s) can be of any simple AL datatype.

- Flow: o; data types: String

An output string in which the '#' and '%' fields have been substituted with the corresponding values.

The following AL code sample shows how to use the STRSUBSTNO function.

Str := 'The balance of account %1 is #2######## $';

AccountNo := 3452;

MESSAGE('The string before STRSUBSTNO has been called:\' +

'%1', Str);

Str := STRSUBSTNO(Str, AccountNo, 2345 + 5462);

MESSAGE('The string after STRSUBSTNO has been called:\' +

'%1', Str);

The first message box will show:

...while the second message box will show:

Note : A maximum of 10 Values can be specified.

The string before STRSUBSTNO has been called:

The balance of account %1 is #2######## $

The string after STRSUBSTNO has been called:

The balance of account 3452 is 7,807 $

STRSUBSTNO

String

Value1, ...

NewString

For Example...

Page 157: Guide to the Navision Al Dbms

SYSTEMVERSION

AL Reference Guide 153

Returns a String, which contain the name and version of the operating system.

String := SYSTEMVERSION()

- Flow: o; data types: String

A string describing the type and version of the operating system. Some typical examples of the format of the returned string are:

This example shows how to use the SYSTEMVERSION function.

Ver := SYSTEMVERSION();

MESSAGE('The operating system is: %1', Ver);

A typical result:

Operating System String

DOS version 6.0 DOS_6.0

AIX version 3.2 AIX_3.2

HP UX version 8.02 HP-UX_8.02

OS/2 version 2.1 OS/2_2.1

The operating system is: DOS_6.0

SYSTEMVERSION

String

For Example...

Page 158: Guide to the Navision Al Dbms

TIME

154 ALReference Guide

Returns the current time set in the operating system.

Time := TIME()

- Flow: o; data types: Time

The current time.

The TIME function can only be used to retrieve the time from the operat-ing system, that is, you cannot use the TIME function to set the time in the operating system.

The following AL code sample shows how to use the TIME function.

CurrentTime := TIME(); {Get the current time

from the operating system.}

MESSAGE('The current system time is: %1', CurrentTime);

A typical result:

The current system time is: 4:15:46.84 PM

TIME

Time

General Comments...

For Example...

Page 159: Guide to the Navision Al Dbms

TODAY

AL Reference Guide 155

Returns the current date set in the operating system.

Date := TODAY()

- Flow: o; data types: Date

The current date.

The TODAY function can only be used to retrieve the current date from the operating system, that is, you cannot use the TODAY function to set the date in the operating system.

The following AL code illustrates how to use the TODAY function.

CurrentDate := TODAY();

MESSAGE('The current date is: %1', CurrentDate);

A typical result:

The current date is: 05/27/94

TODAY

Date

General Comments...

For Example...

Page 160: Guide to the Navision Al Dbms

UPDATEWINDOW

156 ALReference Guide

Updates the Value of a ‘#’-field in the window which is currently open.

UPDATEWINDOW(Number, Value)

- Flow: io; data types: Number

All ‘#’-fields have a specific number. The Number argument is used to determine which field Value will be inserted to in the current window.

-Flow: i; data types: -

The Value (or expression) can be of any simple AL datatype.

The following example shows how to update ‘#’-fields in a window.

AccountInfo := 'Account no. #1######,\' +

'shows a total of #2###### $';

AccNo := 5634;

TotSum := 1000;

OPENWINDOW(AccountInfo, 1, 1);

{Opens a window with '#'-fields for Account no. and Total}

UPDATEWINDOW(1, AccNo); {Fill in field no. 1}

UPDATEWINDOW(2, TotSum); {Fill in field no. 2}

WAITKEYPRESS();

CLOSEWINDOW()

The system will display the following window:

The values of the variables AccNo and TotSum has been inserted in the '#'-fields.

Account no. 5634

shows a total of 1000 $

UPDATEWINDOW

Number

Value

For Example...

Page 161: Guide to the Navision Al Dbms

UPPERCASE

AL Reference Guide 157

Converts the letters in a String to uppercase.

NewString := UPPERCASE(String)

- Flow: i; data types: String

The string to be converted.

- Flow: o; data types: String

The converted string.

The following AL code sample illustrates how to use the UPPERCASE function.

Lower := 'Outstanding Order Status';

MESSAGE('The test-string before UPPERCASE is called:\' +

'%1', Lower);

Upper := UPPERCASE(Lower);

MESSAGE('The resulting string when UPPERCASE has been called:\' +

'%1', Upper);

The first message box will show:

...while the second message box will show:

The test-string before UPPERCASE is called:

Outstanding Order Status

The resulting string when UPPERCASE has been called:

OUTSTANDING ORDER STATUS

UPPERCASE

String

NewString

For Example...

Page 162: Guide to the Navision Al Dbms

USERID

158 ALReference Guide

Returns the current user-ID.

String := USERID()

- Flow: o; data types: String

A string which describes the ID for the current user.

When you enter your application you will be prompted for your user-ID. The USERID function reflects this input.

The following AL code sample illustrates how to use the USERID func-tion.

User := USERID();

MESSAGE('The system was started by %1', User);

A typical result:

The system was started by: JOE

USERID

String

General Comments...

For Example...

Page 163: Guide to the Navision Al Dbms

WAITKEYPRESS

AL Reference Guide 159

Pauses execution of the AL code until Enter or ESC is pressed.

WAITKEYPRESS()

The system will ignore if you press any other key than Enter or ESC.

This AL code sample illustrates how to use the WAITKEYPRESS func-tion.

Str:= 'An arbitrary message to the user\' +

'Press ENTER or ESC to continue';

OPENWINDOW(Str);

WAITKEYPRESS(); {Pauses until ENTER or ESC is pressed}

CLOSEWINDOW();

The above AL code will display the following:

If the execution of the AL code was not paused by WAITKEYPRESS, the user would not be able to read the text in the window, as the system would close the window immediately.

An arbitrary message to the user

Press ENTER or ESC to continue

WAITKEYPRESS

General Comments...

For Example...

Page 164: Guide to the Navision Al Dbms

WINDOWINPUT

160 ALReference Guide

Reads user input in a field (identified by a Number) in a dialog window. The user input is returned in a Variable. The function also returns a NewNumber which identifies the next input field in the dialog window.

NewNumber := WINDOWINPUT(Number, Variable)

- Flow: i; data types: Number

A number which identifies a field in the dialog window.

- Flow: io; data types: -

A variable that may be edited in the dialog window. All AL datatypes are valid.

- Flow: o; data types: Number

The number of the next field in the window. Please observe that if the ESC key is used to leave the window, a 0 will be returned instead.

This example shows how to use the WINDOWINPUT function.

OPENWINDOW(' Activities\' +

' Main Sub Part\' +

' #1######## #2######## #3######## ');

UPDATEWINDOW(1,"MainAct.Code");

UPDATEWINDOW(2,"SubAct.Code");

UPDATEWINDOW(3,"PartAct.Code");

i := 1;

REPEAT

CASE i OF

1 : i := WINDOWINPUT(1,"MainAct.Code");

2 : i := WINDOWINPUT(2,"SubAct.Code");

3 : i := WINDOWINPUT(3,"PartAct.Code");

END;

UNTIL i = 0;

CLOSEWINDOW();

First a dialog window is opened at the middle of the screen. Then a REPEAT-UNTIL loop makes it possible to move between the 3 input fields using the arrow keys or Enter. You quit the loop by pressing Esc. Finally the window is closed.

WINDOWINPUT

Number

Variable

NewNumber

For Example...

Page 165: Guide to the Navision Al Dbms

WORKDATE

AL Reference Guide 161

Returns the work date.

WorkDate := WORKDATE()

- Flow: o; data types: Date

The work date.

This function returns the work date chosen using the Work Date option on the General pull-down menu. If the user has not specified a work date, then this function returns the current system date.

The following AL code sample illustrates how to use the WORKDATE function.

WorkDate := WORKDATE();

MESSAGE('The work date is: %1', WorkDate);

A typical response could be:

The workdate is: 05/27/94

WORKDATE

WorkDate

General Comments...

For Example...

Page 166: Guide to the Navision Al Dbms

WORKDATE

162 ALReference Guide

Page 167: Guide to the Navision Al Dbms

The NAVISION DBMS3Part

The NAVISION DBMS 163

NAVISION is a comprehensive software system comprised of standard, functional modules. It enables simple and speedy registration - followed by control and maintenance - of financial and resource information.

The system provides a set of tools with which you can organize and manipulate data in an intuitive, efficient manner. The effectiveness of these tools, however, can be fully realized only by a user with a clear understanding of the underlying concepts of database management. This manual introduces the concepts necessary for the use of the NAVISION Development System.

All operations on the database are performed by a Database Management System (DBMS). The DBMS is a general purpose software system which supports processes of creating, maintaining and manipulating databases for your applications. Common to both single- and multi-user configurations of NAVISION is that the DBMS allows you to:

• Create, delete and expand databases.

• Create and delete tables.

• Create, delete and change field and key definitions in tables.

• Access database status information.

• Access information about properties of tables, fields and keys.

The DBMS can also be controlled through various programming interfaces, such as:• The NAVISION Application Language (AL). A fourth-generation

language which permits developers to control the DBMS via the NAVISION Development System.

• The NAVISION C-Toolkit interface. A C programming interface which permits developers to control the DBMS from their own C programs.

Page 168: Guide to the Navision Al Dbms

164 The NAVISION DBMS

The Aim of This DocumentFigure 1 gives an overview of the main elements in a NAVISION system. The figure illustrates clearly that the DBMS is the main component as it links your NAVISION applications or C programs to the database. This document will ‘zoom in’ on the individual parts of this figure, and discuss the internal elements.

The following sections will discuss the following topics, based on figure 1:• The first section introduces you to the terms Physical and Logical

database. The main concern in this section is the structure of the Logical database.

• The second section describes the facilities provided by the Database Management System (DBMS) to ensure the integrity of the data and restrict access to the database.

• The third section introduces the NAVISION program interface. This interface enables you to access any subset of records in a NAVISION database, in a specific sorting.

• The fourth section presents special features designed in order to increase the run time performance of NAVISION.

NAVISION MYPROG.EXEvia C-libraryvia AL code

DBMS

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Database

Interface

Database Management System

c: d: f:

Database

Figure 1. Overview of the NAVISION sys-tem.

Page 169: Guide to the Navision Al Dbms

The NAVISION DBMS 165

The Structure of the Database

If you are new to the NAVISION database system, this section will introduce you to some of the most important concepts you need to understand in order to work with data in a NAVISION database. The word ‘database’ is in such common use that we must begin by defining what a database is.

We normally consider a database as a collection of related information, or data. By data we mean some known facts that can be stored and that have an implicit meaning. A typical example is a list which describe the names, addresses and telephone numbers of your customers. These data can be recorded in an indexed address book, or in a disk file using appropriate software. This is a simple example of a collection of related information and hence it is a database.

In this document we will consider a database as a collection of related data which is stored in a computer in a way that enables you to retrive the information you need very quickly.

Physical vs. Logical DatabaseAs a typical database user you are not concerned with where each data item is stored on the hard disk or what its size is; you are only concerned that when a reference is made to for example a Name, the correct value is returned.

This is why the NAVISION database system provides you with a conceptual representation of data that does not include to many details of how the data is stored. An abstract data model is used to provide this conceptual representation. This data model uses logical concepts, such as objects, their properties and their relations, which are easier to understand

This leads us to distinguish between the Logical and the Physical database. When we speak about the logical database we are only concerned with the structures of the data and the relationships between different bits of information, that is, in this description we do not deal with how these structures and relations are implemented. When we speak about the physical database we only deal with how the structures in the logical database and the search paths between them are implemented.

When we use the term database in the following, it should be interpreted as the logical database.

What the user sees as a coherent set of information in the NAVISION database system can be stored on up to 16 physical disk files, but this is transparent to the user.

Figure 2 illustrates how one logical database physically can be stored on three hard disks d:, e: and f:, but nevertheless they still comprise a single (logical) database.

The logical database contains Objects. These objects can be divided into two main categories:

1. Object used by a NAVISION application, that is: Batch, Function, Import, Menu, Report and Window objects

2. Tables

The first category of objects can be seen as basic building blocks providing services needed when we want to insert, modify, delete or show data stored in

The Structureof the Database

Page 170: Guide to the Navision Al Dbms

166 The NAVISION DBMS

The Structure of the Database

the other category of objects, that is, the tables. A typical example of the use of a service provided by the first category of objects, is when we use a window object to show a detailed view of the fields in a record. Another typical use of the first category of objects, is when we use a report object to print, for example, a survey of a budget.

In the rest of this chapter our main concern will be the table objects, that is, we will discuss the logical structures of a NAVISION database.

Logical OrganizationAccess to the data is made possible by a well-defined logical organization composed of:

1. Fields . This is the smallest logical structure used in the NAVISION data-base. A field is used to hold a single bit of information, for example a name ‘Joe’ or an amount ‘2,352.00’. A field can only hold information of a specific type. The NAVISION database system distinguishes between 9 different types of information. Fields are assembled into a structure called a Record.

2. Records . This is a logical structure used to store a single entry in the database. A record consists of a number of fields which are used to store information about important properties of the entry. Records are organised in tables.

3. Tables . A table can be thought of as a n times m matrix. Each of the n rows describe a Record and each of the m columns describe a Field in the record. Tables are organized in Companies.

4. Companies . This is the largest logical structure used in a NAVISION database. A Company may be considered as a sub-database, and its pri-mary use is to separate and group large portions of data in a database. A Company can contain both private tables, and tables shared with other companies.

These logical units will be discussed in the following sections in the same order as in the above list.

e:\database f:\databased:\database

One logical database

Up to 16 physical disk files

Figure 2. The physical database vs. the logi-cal database

Page 171: Guide to the Navision Al Dbms

The NAVISION DBMS 167

The Structure of the Database

Fields and RecordsA field can be considered as a single memory cell capable of holding one single bit of information. In the NAVISION database system 9 different types of fields can be used. Each type is designed to hold a specific kind of information, such as Text, Numbers, Dates and so on. Fields in a record can be one of the following types:

Yes/No . A so-called Boolean data type. Assumes the values TRUE or FALSE, and fills one byte. When formatted, a Boolean field is shown as "Yes" or "No".

Option . Denotes an integer in the range 0 to 255. An Option field fills one byte. An Option type field is defined with an option string, which is a comma-separated list of strings representing each valid value of the field. This string is used when a field of type Option is formatted and its value is converted into a string. An example:

The Option field "Color" is defined with the option string "Red,Green,Blue". Valid values of the field are then 0, 1 and 2, with 0 representing "Red", etc. When the "Color" field is formatted, 0 is converted into the string "Red", 1 into "Green", and 2 into "Blue".

Integer . Denotes integers between -32,767 and 32,767 and fills two bytes.

Long Integer . Denotes an integer between -2,147,483,647 and 2,147,483,647 and fills four bytes.

Decimal No . A decimal number between -1063 and 1063. The exponent ranges from -63 to +63. Decimal numbers are held in memory with 18 significant digits. The representation of a decimal number is a Binary Coded Decimal (BCD). A field of the type Decimal No. fills 10 bytes.

Date. Contains a date value in the range from January 1,1980 to December 31, 2059. An undefined date is expressed as 0. A field of the type Date is stored as an Integer, that is, fills two bytes.

A date value for a normal date is calculated as:

NormalDateValue = 1 + (number of days since 1-1-1980) * 2

That is, all normal dates have odd values. The closing dates are sorted ‘between’ the normal dates:

ClosingDateValue = 2 + (number of days since 1-1-1980) * 2

That is, all closing dates have even values.

The above rules for calculation of normal and closing dates are exemplified in the following table.

Note : All dates have a corresponding closing date. The closing date for a given date is regarded by the system as a period following the given date, but before the next normal date; that is, a closing date is sorted immediately after the corresponding normal date, but before the next normal date.

Page 172: Guide to the Navision Al Dbms

168 The NAVISION DBMS

The Structure of the Database

Time . A type Time contains a value of 1 plus the number of milliseconds since 00:00:00 o'clock, or 0. Time = 0 is an undefined time. A field of type Time is stored as a Long Integer (fills four bytes). A time value is calculated in the following way:

Time = 1 + (number of milliseconds since 00:00:00)

Text . Any alphanumeric string. The field must be defined to be between 1 and 80 characters. The space used by a field of type Text equals the maximum length of the text plus one byte. This extra byte is a used to hold the length of the string. An empty text string has the length zero.

Code . A type code is an alphanumeric string which is right- justified if the contents are numbers only. If letters or blanks occur among the numbers, the contents are left- justified. All letters are converted to uppercase upon entry.

The field must be defined to be between 1 and 80 characters. The space used by a field of type Code equals the maximum length of the text plus two bytes. The first of the extra bytes hold information about the length of the string, and the second byte stores alignment information.

Designing Fields and Tables

Designing a field means assigning it a number of characteristics. These include: its size, the nature of the data it shall hold, its function in the database, security level, etc. Other attributes pertaining to a field are the default values assigned upon record initialization, and the means by which the field can be manipulated. An Integer field, for example, contains only numerical values, and can be used in calculations.

On its own a field is not very useful as it only can hold a limited amount of information. By assembling these small bits of information into Records we get a much more flexible ‘information-holder’. A Record denotes a structure assembled from an arbitrary number of fields. Figure 3 illustrates a record which has 4 fields of different type. Each field occupies a number of bytes as explained in the previous section “Fields and Records” on page 168.

Date No. of days since 1-1-1980 Resulting date value

Undefined - 0

January 1, 1980 0 1

January 1, 1980 (closing) 0 2

January 2, 1980 1 3

January 2, 1980 (closing) 1 4

January 3, 1980 2 5

January 3, 1980 (closing) 2 6

Page 173: Guide to the Navision Al Dbms

The NAVISION DBMS 169

The Structure of the Database

Field and Table design takes place in the NAVISION development system. Each field and each table created receives two forms of identification:• The developer defines an identification number (Integer). This number is

a unique identification which cannot be changed. This number is used by developers working with one of the programming interfaces.

• The developer also defines a name, which is an alphanumeric string serving as a label (such as CUSTOMER or CITY). The name appears in the user interface (on the screen) and should be meaningful and easily understood. This name serves as secondary information, and can be changed at any time.

Besides the ordinary fields discussed in this section, the NAVISION database system also includes 2 special types of fields:• Calculated-fields

• Calc-filter fields

How these special fields provide powerful data manipulation mechanisms is described in the section “Special Database Fields” on page 177.

How the DBMS Keeps Track of Fields and Records

The DBMS keeps track of each field by means of a pair of identifying numbers: the field number which was described above, and the record's primary key.

The primary key is composed of up to ten fields in a record. The value in this field(s) must contain a value which makes it possible for the DBMS to perform a unique identification of each record. This value determines the logical order in which records are stored, regardless of their physical placement on disk.

Logically, the records are stored sequentially in ascending order, sorted according to the value in the primary key field(s). Before adding a new record to a table, the DBMS checks that the information in these fields is unique, and only then inserts the record into its correct logical position. By sorting the records ‘on the fly’ the database will always be structurally correct. This enables fast data manipulation and retrieval.

Jensen

NameNumber AmountModification

date

660203 1267.57 10/14/96

Type: TextLongInteger

DecimalNo.

Date

Size: Max length + 14 10 2

Field

A Record with Four Fields

(bytes)

name:

Fieldno.: 1 2 3 4

Figure 3. Arecord shown asa single row in a

table

Page 174: Guide to the Navision Al Dbms

170 The NAVISION DBMS

The Structure of the Database

TablesThe records in the NAVISION database are organized into Tables. A NAVISION table may be visualized as a two-dimensional matrix, consisting of columns and rows. A table can hold any number of records with a unique primary key, each record consisting of up to 255 fields. However, the total size of a record is limited to 1000 bytes.

Figure 4 shows a table with 6 rows and 5 columns. Each row is a record, and each column is a field..

A table is considered as consisting of two parts: a table description and the table data. The table data is the part users often think of as comprising the database, because it contains the actual records with their data fields. The layout and properties of those fields, however, are specified by the table description. Figure 5 gives an overview of the major elements in a table description.

The table description is used by the DBMS and occasionally by database users who need information about the database structure. You can inspect the table description of any table via NAVISION.

The use of table descriptions makes the DBMS flexible, as it enables the

AccountNo.

Row

s: R

eco

rds

Columns: Fields

No.Date Text AmountConsec.

A Table

Figure 4. The structure of a table: Each col-umn denotes a field, and each row denotes a record.

Keydescription

Fielddescription

- Field Type,

- and other

Table Description

- Key field numbers

Other table

- Name,- Number,- Initial Value,

field properties

properties

Figure 5. The ele-ments of a table description.

Page 175: Guide to the Navision Al Dbms

The NAVISION DBMS 171

The Structure of the Database

system to access tables with different structures. When accessing a table the DBMS can extract the definitions of the table structure from the table description, and thereby correctly access any table.

An important feature of a table description is that the definition of table properties can be used by more than one data table. This is discussed in the section “Companies” on page 176.

A more detailed description of the contents of the table description is given in the list below. Each table description contains the following information:• Table number and name . The table number serves as a unique

identification of a specific table, and cannot be changed once it has been defined. The table name is secondary information, which will be displayed in the user interface. The name can be changed at any time.

• Field Properties . For each field, the following properties are described:

- Type: the nine NAVISION field types described at page 168.

- Number: an integer assigned by the developer during table definition

- Name: an alphanumeric string assigned by the developer during table definition.

- Initial value: the value assigned to the field upon record initialization

- Formatting properties: how the contents of the field are to be displayed on screen and when printed.

- Keying limitations: such as, minimum and maximum values, positive and not blank.

- Entry Procedures: Special tests, adjustments and conversions to be made to the contents of the fields after keying in.

- Relationships: Another table/other tables with which the field will share information.

- State: active or inactive. The state is defined upon table creation, and can be toggled back and forth according to the following simple rule: An inactive field can always be changed to an active field. But an active field can only be changed to inactive if the field is unused (cleared) in all records. This means that if this field contains data in one or more records, this data will have to be cleared before the field can be marked as inactive.

• A list of Keys:

- Key field numbers.

- Sum fields defined for each key (see appendix A).• AL Code. Special tests, adjustments and conversions to be made when

inserting, modifying or deleting from the table.

The list above shows that the table description includes information about the key field numbers. At page 170 we have already briefly discussed the notion of a key; but now that we have introduced you to NAVISION tables, you are ready to learn more about keys.

Keys

A table description contains a list of keys. A key is a sequence of one or more field ID’s from the table. Up to 20 keys can be associated to a table. The first

Page 176: Guide to the Navision Al Dbms

172 The NAVISION DBMS

The Structure of the Database

key in the list is the primary key.

The primary key is always active; the DBMS keeps the table sorted in primary key order and rejects records with duplicate values in primary key fields. Therefore, the values in the primary key must always be unique. Be aware that it is not the value in each field in the primary key that must be unique, but rather the combination of all the fields comprising the primary key.

A maximum of 10 distinct fields can be used in the definition of the primary key. The number of fields in the primary key puts a limitation on the number of fields in the other (secondary) keys.

Some other database systems support unkeyed tables. An unkeyed table is one for which no key fields have been designated, and records are stored in the order in which they were entered in the table. The NAVISION database system does not support unkeyed tables.

Secondary keys

We have already mentioned that up to 20 keys can be associated to a table and that the first is the primary key. All other keys are secondary keys and optional. Secondary keys are used when you want to view records in an order different from the order they are sorted according to the primary key fields.

The number of fields in the primary key affects the possible maximum number of fields in the secondary keys.

This means that if your primary key includes four distinct fields, then your secondary keys can include these four fields, and at most six others. Correspondingly, if your primary key consists of ten distinct fields, then your secondary keys can only consist of combinations of these fields.

A secondary key uses an additional data structure called an index. The idea behind an index is similar to the idea behind the indexes used in common textbooks. A textbook index lists important terms at the end of the book in alphabetical order. Along with each term, a list of page numbers where the term appears is given. We can search the index to find a list of page numbers (addresses) and easily locate the term in the textbook by searching the specified pages. Hence, the index is an exact indication of where each term occurs in the textbook.

When you define a secondary key and mark this key as active, the system will automatically maintain an index reflecting the sorting order defined by the key. Multiple secondary keys may be active at the same time.

A secondary key can be changed into an inactive key. This means that the DBMS does not maintain its index. An inactive key does not take up time or database space during table updates.

Inactive keys can be reactivated; this process may consume some time depending on the size of the table, because the DBMS has to scan the entire table to rebuild the index.

Note : The number of fields in the primary key + the number of fields in a secondary key which do not occur in the primary key, must always be less than or equal to ten.

Page 177: Guide to the Navision Al Dbms

The NAVISION DBMS 173

The Structure of the Database

The fields comprising the secondary keys are not guaranteed to contain unique data; the DBMS does not reject records with duplicate data in secondary key fields. If two or more records contain identical information in the secondary key, the DBMS will use the primary key for the table to solve this conflict. The example below shows how the primary key influences the sorting order when a secondary key has been activated:

We assume that the Customer table includes four entries (records). The records in the Customer table have two fields: CustomerNo and CustomerName. The Keylist for the Customer table is :

The Customer table in the primary key sorting:

When selecting the secondary key, the CustomerName field is used as basis for the ordering. As the contents of these fields are not unique, the records must be subsorted according to the primary key.

The last two records are sorted, reflecting the values in the primary key.

Impact on NAVISION’s Working Speed

Searching for specific data is normally easier if several keys have been defined and maintained for the table holding the desired data. The indexes for each of the keys provide specific views which enables flexibile searches to be performed quickly. However, there are both advantages and drawbacks in using a large number of keys. Consider the following two situations.

Situation A : You mark a large number of secondary keys as active. This will reduce the working speed of NAVISION, when you enter new data, as the system will need time to maintain the indexes for each secondary key. But on the other hand you will now be able to retrive data from the database in several different sorting sequences very fast, because the data already is sorted according to your definitions.

Situation B : You decide to use only a few keys. The working speed will be increased compared to situation A, as the system now only has a few indexes

Key no. Key type Definition

1 Primary key <CustomerNo>

2 Secondary <CustomerName>

CustomerNo CustomerName

001 PC&C

002 IBM

003 Lotus

004 PC&C

CustomerName CustomerNo

IBM 002

Lotus 003

PC&C 001

PC&C 004

Page 178: Guide to the Navision Al Dbms

174 The NAVISION DBMS

The Structure of the Database

to maintain. But now you are not able to retrive your data as easily as before. In order to retrieve the desired data set from the database, you will often have to define or reactivate secondary keys in order to obtain appropriate sortings. Depending on the size of the database, this may consume some time, as the system builds the new index.

The decision whether to use a few or many keys are not easy to discuss in general. The choice of appropriate keys and the number of active keys to use, should be selected as the best compromise between the speed of data retrieval and the speed of data updates (operations which insert, delete or modify data). In general it may be worthwile to deactivate complex keys, if such keys are only used on rare occations.

The overall speed of NAVISION will depend strongly upon a number of factors:• The size of your database

• The number of active keys

• The complexity of the keys

• The number of records in your tables.

• The speed of your hardware, that is, the speed of your computer and its disksystem.

The Key ListFigure 6 illustrates a part of the key list in the table description for the table no. 21 Cust. Ledger Entry in the NAVISION demo application. We consider the first four keys bound to this table - the primary key and three secondary keys. The primary key consists of a single field ID. The first secondary key contains two field ID’s, while the second and third secondary keys respectively contain three and four fields.

Key Description

Primary key

Secondary Key

Secondary Key

Secondary Key

1 (Entry No.)

4 (Date)

3 (Customer No.)

43 (Positive) 37 (Due Date)

3 (Customer No.)

5 (Document Type)

3 (Customer No.)

6 (Document No.)

36 (Open)

Figure 6. An example of a key list from a table description.

Page 179: Guide to the Navision Al Dbms

The NAVISION DBMS 175

The Structure of the Database

CompaniesThe DBMS can access only one logical database at a time, but this database can be divided into one or more companies. A company is a "sub-database", and its primary use is to separate and group data in the same database. As mentioned at page 170 fields and tables are identified by a number. Companies are not identified by a number, but by a name. A company "bundles" one or more data tables together, into a logical superstructure which is identified by a company name. Other than the shared company name, the different tables within a company have nothing else in common. Opening a company is your first step after opening the database or connecting to a server.

Figure 7 shows a database with four tables. The four table descriptions, appearing to the left, apply to each of the data tables, which are logically sorted into three companies. The records in the tables G/L Account, Customer and Vendor, all have the same structure and the same field definitions, even though they belong logically in three different companies. Only the data stored in the fields differ.

The idea of a company can be explained by an analogy with records in AL: When working with records in AL you can use a WITH statement in order to tell the system that all references you make to fields, is to fields within a specific record. That is, within the scope of the WITH statement, you do not explicitly need to refer to record.field but just to field. One could say that record is assumed as default. Likewise, by opening a company you specify a default group of tables to which all your database accesses will be directed to.

Even though you have selected a specific company, you can still access data in any table in any other company. In order to do so, you must use the AL function dbSELECTCOMPANY to explicitly define which other company you want to access.

Multiple applications can access the same company and the same table(s) at one time. How the DBMS controls these multiple accesses are described in the section “Table Locking” on page 185.

Data

Data

Common Data

Data

Data

Data

Data

Data

Data

DataG/L Account

Customer

Vendor

Printer Selection

Company

B CTable Description ACompanyCompany

Figure 7. This illustratessharing of data between

different conpanies

Page 180: Guide to the Navision Al Dbms

176 The NAVISION DBMS

The Structure of the Database

Special Database FieldsIn addition to the conventional data fields, which simply hold values, two kinds of specialized fields are available for data manipulation:• Calculated fields

• Calculation filter fields

Calculated Fields

Calculated fields is a powerful feature in the NAVISION database system. The Calculated field is a fundamental concept which highly influences the way a NAVISION application is designed.

Calculated fields and the underlying concept of Sum fields have been designed in order to increase the performance in activities, such as calculating the balance of your customers, which in traditional database systems involves a series of accesses and calculations before a result is available. Why such a result will be immediately available via the use of Calculated fields will be clear as you read through the rest of this section and Appendix A, which deals with the underlying concept of Sum fields.

Calculated fields are not stored together with the table data, why a Calculated field can be thought of as a virtual field, which is an extension to the table data. When a table is opened, the values in Calculated fields are set to 0 (zero). In order to update a calculated field, the programmer must use the AL function dbCALCFIELDS or the C-Library function DBL_CalcFields().

There are two types of Calculated fields:• Yes/No . A Calculated field of this type is used to signal if any records

exists within a specified range in another table.

• Decimal No. A Calculated field of this type contains the sum of a column within a specified range in another table.

Figure 8 illustrates a Customer table in which the records contain a calculated field of the Yes/No type named AnyEntries. The value in this Calculated field reflects whether there exists any entries (records) for each of the customers.

The Customer table in figure 8 also contains a Decimal No. type Calculated field named Balance. As illustrated in the figure, the Calculated field Balance, reflects the sum of specific subsets of a column in the Customer Entries table.

The figure shows that the value in the Calculated field Balance for customer no. 10000 (Windy City Solutions), is retrieved from the Amount column in the Customer Entries table. The value is the sum of the amount fields for the entries which have the customer no. 10000, that is:

Sum = 10 + 20 + 30 = 60.

The values shown in the Balance column in the Customers table for customer no. 10010, 10020, 10040 are found in the same way. Customer no. 10030 has the value 0 (zero), as there are no entries in the Customer Entries table which has a CustNo that equals 10030.

In this example each calculated field in the Customers table reflects the sum of a specific subset of the Amount fields in the Customer Entries table. How

Page 181: Guide to the Navision Al Dbms

The NAVISION DBMS 177

The Structure of the Database

the calculation of a calculated field is to be made, are defined in a Calculation Definition.

Each Calculated field has an associated Calculation Definition which includes the following information:• Table ID . Identification of the table that hold the information to be used

in the calculated field.

• Filter . A list of filters to be used in the computation of the Calculated field. The filters can be either:- Constant expressions- Values from ordinary fields- Calculation Filter fields (which are discussed in the next section)It is a requirement that there exists a key for the other table, which includes the fields used in the filters.

The next two elements in the Calculation Definition are only used for Calculated fields of the Decimal No. type.• Sum Field . Defines the field in the sub-table which is used as basis for

the computation of the Calculated field. It is a requirement that the field (in the sub-table) to be summed is defined as a sum field in the key

10040

10030

10010

10000

10020

CustNo Name CountryCode Balance

Customers (Table data)

10010

10010

10000

10000

10000

CustNo Date Comment Amount

10020

10020

10020

10040

10040

10040

Customer Entries (Table data)

10

20

30

40

50

60

70

80

90

100

110

Modern Cars Inc.

Jean Saint Laurent

Russel Publishing

La Cuisine Francais

Windy City Solutions US

US

FR

UK

FR

Virtual part of the table data

(calc. field)

60

210

300

90

0

Yes

Yes

No

Yes

Yes

(calc. field)AnyEntries

Figure 8. Calcu-lated fields in theCustomer table.

Page 182: Guide to the Navision Al Dbms

178 The NAVISION DBMS

The Structure of the Database

definition. Sum fields are the basis for the operations and flexibility provided by the Calculated fields. Sum fields are discussed in appendix A.

• Reverse sign . Makes it possible to shift the sign of the result in the Calculated field.

The second special database field, the Calculation Filter field, is used in connection with the above mentioned list of filters.

Calculation Filter Fields

End users may want to limit calculations to a subset of values in a column which has some specific properties. For example the user may want only to sum up the amounts of customer entries which are entered in april, or for customers who have customer numbers greater than 10040. This is possible if the application has been designed using Calculation Filter fields in connection with the Calculated fields.

Figure 9 illustrates the relations between various types of database fields and the Calculation Definition. The filters defined in the Calculation Definition can consist of constants, values from ordinary fields and of filters given as parameters in Calculation Filter fields. Calculation Filter fields are fields in which the end user can input a filter (via the user interface in a NAVISION application), which will affect the calculation of a calculated field. The computation of a Calculated field is only affected if the Calculation Filter field is used in the filters in the Calculation Definition..

Table A

Calc. fields

Calc. filter fields

Ordinary fields

Calculation

Definition

Table B

Table C

Table D

: Path for information used in Calculation Definition

: Path for data used in computation of Calc. Fields

Constants

Figure 9.The con-nection between Calculation Fil-ter fields, the Cal-culation Definition and Calculated fields

Page 183: Guide to the Navision Al Dbms

The NAVISION DBMS 179

Important Tasks for the DBMS

In this section we discuss some important tasks for the DBMS. The topics described in this section cover some of the most powerful features in the NAVISION database system.

A main task for the DBMS is to protect your data from any kind of damage or corruption. The data protection mechanisms build into the NAVISION DBMS are illustrated in figure 10, which gives a structural overview. As the figure suggests, the data protection mechanisms fall into two main categories.

Mechanisms to ensure the...

1. Data integrity . We explain how the DBMS manages the integrity of your data.

2. Data security . We present the techniques used to protect the database against persons who are not authorized to access the database.

The concrete combination of features in your NAVISION system is highly dependent upon the configuration of the database; whether it is running single-user or multi-user, that is, whether it is implemented locally or across a network.

Although the concepts of data integrity and data security are quite distinct, there are some similarities between them. Both these concepts can be stated in terms of constraints:• Integrity is specified in terms of integrity constraints, whereas security is

specified in terms of authorization constraints.

• The DBMS monitors the user interaction with the database to ensure that both integrity and security constraints are observed.

Data IntegrityData integrity deals with the reliability of the data stored in the database, that is, the requirement that the database must describe the real world as credible as possible. The NAVISION means to obtain data integrity are described in the following sections:• Write Transactions and Recovery . We present a logical unit of

Logical Database

Data Protection:- Data Integrity- Data Security

DBMS Tasks

Figure 10. The DBMSincludes mechanisms toensure the data integrity

and the security.

ImportantTasks for

the DBMS

Page 184: Guide to the Navision Al Dbms

180 The NAVISION DBMS

Important Tasks for the DBMS

database processing called a write transaction, and we discuss the NAVISION strategy for recovery from transaction failures.

• Read Consistency and Concurrency . We discuss the mechanisms which assures consistency of the data when you read from a database in a multi-user environment.

• Table Locking . We explain how the DBMS ensures the integrity of the data in a multi-user environment.

• Deadlock Detection . We explain the problem of deadlocks, and the NAVISION strategy for solving it.

• Commit . We discuss the differences between committing database updates when using AL and C code.

Write Transactions and Recovery

We define a write transaction in NAVISION as an atomic unit of work on the database, which is either completed in entirety or not done at all. In other words, a transaction is a way to encapsulate a sequence of read and write operations on the database, in order to ensure that either all or none operations are performed on the database. The concept of write transactions is a general NAVISION facility which are used both in single- and multi-user environments.

When a transaction is submitted to the NAVISION DBMS the system is responsible for making sure that:• All operations in the transaction is completed successfully and their effect

is recorded permanently in the database, or

• The transaction has no effect whatsoever on the database.

The DBMS must prevent that some operations of a transaction are applied to the database while others are not. A situation like this can occur if a transaction fails while executing the operations of a transaction.

Some typical reasons for a transaction to fail are:• The user decides to abort the transaction.

• System crash, due to hardware or software errors.

• Operation errors, such as overflow or division by zero.

If the transaction is aborted all tables are restored to the state they had before the transaction started.

A typical example of a write transaction is illustrated by a banking system where $100 must be transferred from one account to another. This involves two operations in a single database:• Subtract $100 from account A

• Add $100 to account B

If a power failure or some other fatal error interrupts the program after the first operation, the database is not in a consistent state, because the second operation has not been completed. By bundling both operations into a single transaction, either none or both of the operations are executed, and the data will always be consistent.

Page 185: Guide to the Navision Al Dbms

The NAVISION DBMS 181

Important Tasks for the DBMS

More on Write Transactions

In the previous section you learned that by bundling a number of operations on the database into a single transaction, we can asure that the database is consistent no matter whether the transaction is committed or aborted. The way NAVISION handles write transactions and at the same time keeps the database consistent, is different from the traditional approach. Traditionally database systems contain a facility that automatically maintains a log file which records all changes to the database. This log file contains images of the record before it is modified and after it is modified, so-called before and after images. The changes recorded in the log file can be used to recover the database from failures.

Assume that an application program aborts because of power failure, or is aborted by the operator. The database is now in an inconsistent state, and all modifications already made to the database must be cancelled. In common database systems this is achieved by so-called Roll back recovery, that is, by backing out the updates of the application program. This backout is performed by reading the log file backwards and performing the recorded changes to the database, until the point where the application program started. This restores the modified records to their original contents.

The NAVISION DBMS does not need to use a log file, as the NAVISION database is data-version oriented. This means that each time a transaction is committed, a new version of the database is created. While you enter new data in the database your changes are private, first when you commit the changes, the new data becomes public and establishes the newest version. The DBMS enables different applications to access and modify the database concurrently by letting them work on individual versions which are snapshots of the database at the point in time where the applications start to access the database. The advantages of the data version approach will become clear as you read through the following sections.

Read Consistency and Concurrency

NAVISION is data-version oriented, meaning that each time a write transaction is performed, a new version of the data in the database is created. Figure 11 shows three applications accessing the same database. Imagine that the first access is made by a report. The second access is made by a user who inserts new entries in the database, and the third access is made by a backup

Page 186: Guide to the Navision Al Dbms

182 The NAVISION DBMS

Important Tasks for the DBMS

procedure.

The generation of a report in figure 11 is a time consuming process, and while the report is generated, another user enters or modifies records in the database. When each entry is committed a new version of the database is created, but as the report started, a snapshot of the database was made and the report continues to work on version A of the database. A third user starts a backup procedure. At the point in time where this process is started, the most recent version of the database is B, and a snapshot of the database is made, why the backup process is not influenced by the second user who continues to enter new data durring the backup process. This example shows that working with dataversions makes it possible for many users to acces the database without interfering with each other.

The implications of the data-version approach are many; most important is that different applications may be reading different versions of the same database. These versions are snapshots of the database at the point in time where the applications start to access the database. In this way the DBMS allows for concurrency while still maintaining read consistency. If the accesses involve only data retrieval and no changes, then the newest version will persist - for all applications - until a write transaction is performed.

When you update the database, your modifications are private. First when you commit your updates does your modifications become public. Your newly committed updates plus the part of the database which was not modified makes up the newest version.

Figure 12 illustrates the concept of data versions. The data in the NAVISION database is stored in a well known data structure which resembles a tree. A tree data structure is formed of nodes. Each node in the tree, except for a special node called the root, has one parent node and one or more child nodes. The root node has no parent. A node that has no child node is called a leaf; a nonleaf node is called an internal node. The level of a node is defined as one more than the level of its parent, with the level of the root node being zero.

The data structure used in the NAVISION database is called a B+ tree. This means that the tree structure is balanced and that the data (records) are only stored in the leaf nodes, not in the internal nodes. A balanced tree has the advantage that there always is a minimum number of levels in it, why all search paths will be the shortest possible. A B+ tree structure is an efficient

Time

Report

Backup

Entry

Version A B C D

(A)

(B)

Figure 11. Three application accessing differ-ent version of the database

Page 187: Guide to the Navision Al Dbms

The NAVISION DBMS 183

Important Tasks for the DBMS

data structure which enables fast searches to be performed.

Imagine that the tree structure in our database contains a branch with customers A, B and C. Furthermore there are two free database blocks available.

Assume that you need to modify customer A and C. When you update the records, the DBMS makes a copy of the original. As illustrated in figure 12, the copies will use two free database blocks. You will then perform your modification to the copies, and the system will create a new internal node.

If an error occurs during the transaction or the user decides to abort the changes, the database blocks occupied by the copied branch will be released and be available for new database updates.

If the transaction is committed, this new internal node will replace the old node, and the database blocks used by the old versions of customer A and B will now be available as free database blocks which can be used by database updates.

The database contains a number of historical versions. Gradually, as the free area in the database is consumed by succeeding historical versions, new versions begin to replace the oldest versions.

Slow operations can run into trouble in this environment. Suppose Application A is reading data from the latest version, while generating a very time-consuming report. In the meantime, Application B begins performing write transactions which consist of order entries.

As order entries are added to the database, newer versions of the database is created. The maximum number of historic versions in your database, depends on the space in the database which currently is not used by the newest

Figure 12. Illus-tration of free

database blocksand data versions

B C

B C

A1

C1

A

A

FreeFree

Data Versions

Database

Database

Version 1:

Version 2:

Page 188: Guide to the Navision Al Dbms

184 The NAVISION DBMS

Important Tasks for the DBMS

version, that is:

At some point the data version accessed by A becomes the oldest complete data version. But B needs a database block from this version so it can complete its modifications.

This conflict is solved by the DBMS by giving priority to the write transaction and ejecting application A. A runtime error message is sent to A on its next read operation - "Data version is no longer valid" - and it is forced to restart the entire process with the newest version. But as long as B continues and the space in the database available for historic versions remains the same, there is little hope that A will be able to generate the report.

Table Locking

In multi-user environments the DBMS ensures the integrity of the data, by setting write locks on all the tables you are updating. This prevents other users from making changes to the same tables.

While write operations automatically lock a table during updates, you can explicitly lock a table, even if you are not certain a write operation will be performed. By locking a table immediately before accessing a record, you are assured that the data you eventually might change in the record conforms to the data you have read, even if some time passes in between. A write lock does not influence data retrieval; that is, although a table is locked, it does not prevent other users from read access to the records in the table.

A write lock is active until the write transaction is either aborted or committed. Figure 13 uses pseudo language mnemonics to illustrate the

The maximum defined size of the database- The amount of space currently used to hold the newest version

Space available for historic versions

Page 189: Guide to the Navision Al Dbms

The NAVISION DBMS 185

Important Tasks for the DBMS

scope of write locks.

The figure illustrates both an explicit lock and an automatic lock. Line (1) in the write transaction explicitly locks table A. If this explicit lock was not set on table A, the DBMS would automatically lock this table when a record is inserted (3). Table B is not locked explicitly, but is locked automatically by the DBMS when a record is inserted (4). Both locks are active until the ‘End Write Transaction’ command is executed in line (5).

Deadlock Detection

The correct functioning of a multi-user system will depend on the coordination of the activities. If a transaction process requires write access to several tables at once, care must be taken to avoid the situation where it can obtain access to some of the necessary tables and another transaction process can obtain others of them, but where neither of them can proceed without the other finishing. This causes both of the transaction processes to wait for the other transaction process to finish. As a result both processes will have to wait forever. Such a situation is known as a Deadlock (or as Deadly Embrace).

In order to avoid deadlock situations, the DBMS has been provided with an automatic deadlock detection mechanism, which detects these situations and ejects one of the write transactions. Figure 14 illustrates how a deadlock can

.

.BeginWriteTransaction; LockTable(TableA) (1) FindRec(TableA, ...); (2) . . InsertRec(TableA, ...) (3) . InsertRec(TableB, ...); (4) . . . . .EndWriteTransaction (5)..

Table Locking

Tabl

e A

lock

ed

Tabl

e B

lock

ed

Figure 13. Thescope of write

locks

Page 190: Guide to the Navision Al Dbms

186 The NAVISION DBMS

Important Tasks for the DBMS

occur.

The DBMS will always eject the application which causes the deadlock to occur, cf. the example shown in figure 14. This rule applies for any number of applications involved in a deadlock.

Commit in AL and C

Although the concept of committing an update is the same whether you are using AL code or the C-Library, there are some minor differences. This subsection explains these differences in detail.

When you want to perform an update using the C-Library, the first thing you must do, is to explicitly tell the system that you want to perform a write transaction by using DBL_BWT (BeginWriteTransaction). Likewise you must use DBL_EWT (EndWriteTransaction) to explicitly tell the system when your write transaction ends.

When you use AL code to perform updates to a NAVISION database, these BeginWriteTransaction and EndWriteTransaction statements are handled implicitly by the system, that is, the system automatically executes these commands before the AL code is entered, and when the AL code has been executed. This means that if you only need to perform a single write

Application 1 Application 2

Tim

e LockTable(A)

Table A now LockedLockTable(B)

Table B now lockedLockTable(B)

Wait for table B tobe unlocked LockTable(A)

Wait for table A to

be unlocked

The DBMS detects a deadlock situation, andejects application 2.

Table B locked

AAAAAAAAAAA

AAAAAAAA

AAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAAAAAAAAA

AAAAAAAAAAAAA

AAAAAAAAAAAAAAAA

AAAAAAA

Application 2 ejectedand transaction aborted.Lock attempt on Table Acancelled and Table Bautomatically unlocked

AAAAAAAAAAAAAAAAAAAAAAAA

Figure 14. The automatic dead-lock detection ejects one of the applications

Page 191: Guide to the Navision Al Dbms

The NAVISION DBMS 187

Important Tasks for the DBMS

transaction you do not have to commit your update explicitly, it is done automatically by the system. But if you need to perform more than one write transaction, you have to use dbCOMMIT() in order to separate the transactions.

Figure 15 illustrates these differences. The AL code contains two write

transactions. As the execution of the AL code begins, write transactions are automatically enabled. By issuing the command dbCOMMIT(), you tell the system that the first write transaction has ended, and prepares the system for the second. As the execution of the AL code has been completed, the system automatically ends the second write transaction. When using C code to perfom the same transactions, each transaction must explicitly be encapsulated by DBL_BWT() and DBL_EWT() commands.

Database Security and ProtectionSome information may by considered as confidential or private, and cannot be accessed legally by unauthorized persons. For example, several states in the U.S. have privacy-of-information laws.

NAVISION provides several means of protecting data: • Access control . The NAVISION DBMS includes a password check

which prevents unauthorized persons from accessing the system itself.

• Authorization control . The NAVISION DBMS provides techniques to enable certain users in a multiuser system to access selected portions of the database. We distinguish between direct authorization and authorization via objects.

• Data encryption . Furthermore the NAVISION database is encrypted to protect sensitive data.

Every multi-user system demands the access protection provided by these features.

User Access Control

In a multiuser NAVISION environment, where several users are able to access the same database, each user must login and supply a password. The DBMS stores a table of user IDs and passwords; these can be defined and

BeginWriteTransaction

AL Module

AL Statements

dbCommit(...)

AL code C code

DBL_BWT();

C code

DBL_EWT();

DBL_BWT();

DBL_EWT();

C code

}}

}

}

1. Trans.

2. Trans.2. Trans.

1. Trans.

EndWriteTransaction

AL Statements

Figure 15. Dif-ferences in com-mitting updates

in AL and C code

Page 192: Guide to the Navision Al Dbms

188 The NAVISION DBMS

Important Tasks for the DBMS

modified whenever the database is open. A user may change his password at any time, but only a special user, the super user is authorized to create, change and delete users, passwords and user rights.

Direct User Authorization

The NAVISION DBMS includes a database authorization subsystem which ensures the security of portions of the database against unauthorized access. This is done by assigning different privileges to different classes of users.

Users can be divided into groups which have destinct rights. For example if there are several people who use the system to enter orders and nothing else, the super user could define a group with the appropriate rights.

The access privileges can be defined explicitly for all Table, Function, Window and Menu objects.• Table objects . The access privileges for table objects can be set to:

- No Access. This prevents the user from access to the table in any way.

- Read Access. This enables the user to read data from the table, but pre-vents the user from inserting or modifying data in the table.

- Read/Write Access. This enable the user to both read and write data.

• Function, Window and Menu objects . The access privileges for these objects can be set to:

- No Access. This prevents the user from accessing the object.

- Access. This enables the user to access the object.

The access privileges cannot be explicitly defined for other database objects than the above. If, for example, you try to run a report object which needs access to a window or a function object for which you do not have access rights, an error message will occur. In other words: you cannot use objects which needs access to other objects for which you do not have the appropriate access rights.

Authorization via Objects

Although a user’s access to the database is restricted to specific areas, extended user authorization can be granted via objects.

The super user can authorize any user access to, for example, a function object which, in turn, allows access to parts of the database which cannot directly be accessed by the user. The authorization to access these parts of the databasen is defined by the developer when the function object is created, or in other words: the extended authorization is defined inside the object.

Encryption

Security precautions continue after database manipulation stops; all data stored to disk are automatically encrypted. The encrypted data cannot be deciphered by low-level editors or disk utilities; only proper, authorized accesses will yield legible material.

Note : If there is not at least one user designated as super user, the system will consider all users as super users.

Page 193: Guide to the Navision Al Dbms

The NAVISION DBMS 189

Interfacing the DBMS

This section describes the NAVISION program interface. This interface enables you to access any subset of records in a NAVISION database, in a specific sorting order using a NAVISION application or your own C program.

When you work on a table, a specific task will often require access to the records in another sorting than the one defined by the primary key, that is, your specific task requires the use of another key. Furthermore if the table you work on contains a large number of records, you will often only need access to a small subset of records, which have one or more properties in common. The NAVISION means to support such data retrieval facilities are:• Table handles . The DBMS assigns a handle to the table you want to

access. A current key and one or more filters can be assigned to the table handle.

• Current key and filters . Makes it possible to change your view of the records in a NAVISION table.

Figure 16 illustrates an application (NAVISION or C program) which accesses a table in a NAVISION database via three handles. By using three different handles, it is possible to get three distinct views of the records in the table.

Table HandlesWhen a table is closed it is identified only by a number defined by the developer when the table was created. However, when an application requests for access to a specific table, the DBMS assigns the table a table

Application

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAAAA

AAAAAA

DatabaseInterface

DBMS

retrieving data

Table Table...

Table...

Database

Handle Handle HandleTable Handle:Current keyFilter(s)

Figure 16. An applica-tion retrieving data

from a table using threediffrent table handles,each with distinct cur-

rent key and filters.

Interfacingthe DBMS

Page 194: Guide to the Navision Al Dbms

190 The NAVISION DBMS

Interfacing the DBMS

handle. A handle can be thought of as a container which hold a current key and one or more filters. This handle is returned to the application, and is now ready to serve as a direct link to the table. Access to the table is only possible via this handle.

When your application access a NAVISION table via a handle, all its records are accessible. Alternatively, you can define another view of the table by assigning a key and filters to the table handle. This allows you to open various "views" of a single table, each with its own set of filters and a key.

Current keyAs discussed in the section “Secondary keys” on page 173, the DBMS can maintain up to 19 secondary keys. These secondary keys can be used when you want to view records in an order different from the order they are sorted according to the primary key fields. When you select a secondary key to be used instead of the primary key, the newly activated secondary key is called the current key.

An example: assume that the table Customer includes four entries (records). The records in the Customer table have two fields: CustomerNo and CustomerName. The Keylist for the Customer table is:

When using a handle, your default view of the records in the Customer table will be sorted according to primary key:

Alternatively you can assign key no. 2 to the table handle, that is, define the current key to be key no. 2. This changes your view of the Customer table into:

FiltersA filter can be set for any field in any table, to limit the number of records upon which operations such as searches and calculations are based. When

Key no. Key type Definition

1 Primary key <CustomerNo>

2 Secondary <CustomerName>

CustomerNo CustomerName

001 PC&C

002 IBM

003 Lotus

004 PC&C

CustomerName CustomerNo

IBM 002

Lotus 003

PC&C 001

PC&C 004

Page 195: Guide to the Navision Al Dbms

The NAVISION DBMS 191

Interfacing the DBMS

accessing a NAVISION table via a table handle, you can assign one or more filters to the handle, in order to suit your specific task.

You can apply a filter to one or more fields and then perform a task that would typically affect all of the elements in the table, but now that you have applied a filter, only those elements that fulfil the conditions of the filter are affected. When you apply a filter to more than one field, there will implicitly be a logical AND between these filters.

Figure 17 gives an example of the use of filters, and illustrates the effect of the implicit logical AND between the filters. Suppose you want an overview of the French customers in your Customer table. This can be obtained by applying the filter ‘FR’ to the Country field in the Customer table. Furthermore you want to see which french customers have a credit limit greater than $3000, so you will also have to apply the filter ‘>3000’ to the Credit limit field.

As figure 17 illustrates, you have two french customers, no. 10020 and 10040. But as customer no. 10040 has a credit limit less than $3000, your view of the table will only show one customer, namely customer no. 10020 Jean Saint Laurant who has a credit limit of $5000.

A filter is a composite string, containing one or more of the operators shown in the table below:

Operator Meaning Example Explanation

.. Range 30..40 Numbers between 30 and 40, inclusive

..310790 Dates till 310790, inclusive

| OR 5 | 6 The number 5 or 6

& AND 5..15 & 1..9 Numbers from 5 to 9, inclusive

<> Different from <> 0 Number that is not zero

> Greater than > 100 Number greater than 100

Number CustomerName CountryCodeCreditLimit

10040

10030

10020

10010 Modern Cars Inc. 400

Russel Publishing

5000

1500

10000 Windy City Solutions

Filters: >3000 FR

Jean Saint Laurant

La Cuisine Francais

34000

1000

US

US

FR

UK

Table:

FR

Filters

10020 5000 FRJean Saint Laurant

Your View:

Figure 17. Applyingfilters on the Cus-tomer table to find

french customerswith a credit limit

greater than $3000

Page 196: Guide to the Navision Al Dbms

192 The NAVISION DBMS

Interfacing the DBMS

Operator Hierarchy

The operators used in filter expressions are organized in four hierarchical groups which determines the order in which the operations are carried out. The lower the number of the group, the higher the precedence: The four groups are:

1. .. (Range), () (parentheses)

2. <, >, <=, >=, <>, ?

3. & (AND)

4. | (OR)

The hierarchy causes the apparently identical expressions below to produce different results:

Expression 1: <10 | 30..40 & >= 35, evaluates to: <10 | 35..40

Expression 2: (<10 | 30..40) & >= 35, evaluates to: 35..40

Figure 18 illustrates the difference between these expressions.

>=Greater than or equal

>= 10 Number greater than or equal 10

< Less than < 100 Number less than 100

<=Less than or equal

<= 100 Number less than or equal to 100

? Contains ?Ltd. Text containing "Ltd.".

Expression 2:

Expression 1:

35 4010

35 4010

Effect of Operator HierarchyFigure 18. The ranges of two apparently identi-cal expressions.

Page 197: Guide to the Navision Al Dbms

The NAVISION DBMS 193

Features for Increasing Performance

This section describes special features designed to increase the run time performance of NAVISION. We will present the following features:• The DBMS Cache

• The COMMIT Cache

• The Command Buffer

The DBMS CacheThe DBMS Cache is a buffer storage which holds copies of portions of the database which currently is being used by the DBMS. As long as required data is in cache, data appears as being immediately available. When required data is not in the cache, required data must first be brought in from the disk.

The Cache is transparent to the user/programmer:• Data is brought into cache automatically and copied back to the physical

disk automatically.

• No instruction are required to do these transfers.

• The user does not have to know of the cache’s existence for the program to work correctly, but the developer has to be aware of the caches existence for the application to work well.

Figure 19 illustrates applications sending requests to the DBMS. When, for example, Application 2 sends a request to read data from the database, the request handler determines if the desired data can be fetched directly from the cache, or if the data must be fetched from a disk.

At the same time another application could be modifying a record in a table in the database. This modification will be written to the DBMS cache, not to the disk. When this application ends the write transaction (commit the

Application 1 Application 2 Application 3

DBMS

Network

Database

DB Request Handler

Cache

: Data flow

Figure 19. TheDBMS Cache.

Features forIncreasing

Performance

Page 198: Guide to the Navision Al Dbms

194 The NAVISION DBMS

Features for Increasing Performance

changes), the data in the cache modified during the transaction will be written to the disk; the cache is said to be flushed.

The DBMS Cache always holds the most recently used data. The cache automatically replaces parts of the cache memory with relevant parts of the database.

The size of the cache has great impact on the performance. Two simple rules apply when determining the size of the cache:• The more memory you assign to your cache, the more efficient the cache

will be (Of course there are no reason to assign more memory to the cache than the total size of your database).

• The size of the cache should not exceed the amount of physical memory available on your system, as this may cause your operating system to swap the cache memory out and in from disk; this will slow down the overall speed of your NAVISION system tremendously.

Nevertheless, there are upper limits for the DBMS Cache size. The maximum cache size in DOS and OS/2 versions of NAVISION is 6400 KB, while the maximum size in UNIX versions are 32000 KB.

The Commit CacheThe Commit Cache is a special write buffer storage for the disk(s) in your system. The Commit Cache has been designed to:• Quickly absorb committed transaction from the DBMS. This frees the

DBMS for other tasks

• Enable asynchronous disk writes

• Enable parallel disk writes when using multiple disks

• Guarantee that the disk file always is consistent

The Commit Cache is placed between the DBMS and the database, and absorbes committed transactions from the DBMS. When the Commit Cache has received a committed transaction, it takes care of writing the data to the disk(s). In this way the DBMS is free to perform other tasks while data is being written to the disk. The data is said to be written asynchronously to the disk, as the time for the disk write is independent of the time when the transaction was committed by the DBMS.

As described in the section “Physical vs. Logical Database” on page 166, the logical database can be stored in up to 16 distinct disk files (disks). When using more than one disk, each of these disks are controlled by a separated commit cache process, which are linked to each other in order to enable and control (asynchronous) parallel write operations.

The Commit Cache always guarantees that data is written to the disk in the same sequence as the data is sent to the Commit Cache. This assures that the database file always is consistent. The database file is consistent, even if a power failure should occur during a write operation to the disk.

However, the data which is currently held in the Commit Cache memory when a power failure occurs, is lost, and must be re-entered via the

Page 199: Guide to the Navision Al Dbms

The NAVISION DBMS 195

Features for Increasing Performance

NAVISION user interface.

Figure 20 illustrates a database stored on three physical disks. Each disk is controlled by its own commit cache process. All processes are connected to enable parallel writing.

The Command BufferThe Command buffer is placed as a link between your application and the DBMS in your NAVISION system. The Command buffer is a temporary storage place which can hold requests (AL database commands) sent from your application to the DBMS. The Command buffer has been designed in order to reduce the number of network transfers, when using NAVISION in LAN environments.

When an application performs a write transaction, some requests such as for instance inserting a record in a table (dbINSREC), does not need to be send to the DBMS at once, but can be temporarily stored in a Command buffer. In general, commands which are not to return a value in order for the execution of the AL code to continue, does not need to be send immediately to the DBMS..

The advantage of assembling DBMS commands into packages, is that the number of network transfers will be reduced (that is, the load on the LAN will be reduced), as the time required to send one DBMS request is comparable with the time used to send an entire package.

The following illustrates an AL code sample where the command buffer

Note : Do not use advanced disk caches with delayed write back (sometimes called lazy write). This may cause your database file to be corrupted.

Note : The contents of the command buffer is sent to the DBMS when the buffer is full, or when a command requires an immediate response from the DBMS.

DBMS

c: d: f:

SeparateProcessSeparate

ProcessSeparate

Commit Cache

Database

Process

Figure 20. TheCommit cache

enables asynchro-nous parallel writ-ing to the disks in

your system

Page 200: Guide to the Navision Al Dbms

196 The NAVISION DBMS

Features for Increasing Performance

affects the number of network transfers.

WHILE dbFINDREC(Rec, �-�) DO

dbDELREC(Rec);

Two commands are executed for each record in the table, but each record will only cause one request to be sent to the DBMS, as the dbDELREC command will be stored in the Command buffer until the dbFINDREC command is executed.

The system automatically turns off the Command buffer when you activate the AL debugger, as unexpected results may occur if it is used when debugging. Nevertheless, if an error occurs at run time, and you enter the AL editor in order to find a potential bug in your code, a special situation may occur as the Command buffer always is active when an application is executed. Consider the following example:

(1) dbINSREC(CustomerA);

(2) dbINSREC(CustomerB);

(3) dbINSREC(CustomerC);

(4) IF dbFINDREC(CustomerX) THEN ...

If CustomerB inserted in line (2) already exists in the database, a run time error will occur. But the error will not occur before the IF statement in line (4) is executed, as the commands in line (1), (2) and (3) are stored in the Command buffer until the dbFINDREC command must return a value in order for the execution to continue.

When you enter the AL editor, the cursor will be placed on line (4), and the following error message will be shown:

This might seem to be a rather strange error message for line (4), but the explanation is simple: the error message applies to line (2), but the error was not encountered by the DBMS until line (4) was executed by your application.

The Customer �B� already exists.

Page 201: Guide to the Navision Al Dbms

Sum FieldsAAppendix

Sum Fields 197

A sum field is a fundamental feature which forms the basis for the concept of Calculated fields. Sum fields permits fast calculation of sums of numeric columns in tables, even in tables with many thousands of records.

A sum field is associated to a key; each key can have at most 10 sumfields. During database design, a field of the Decimal No. type can be associated to a key as a sumfield. This tells the DBMS to create and maintain a structure which contains the accumulated sum of values in a column. When a new current key is selected, any sum fields associated with it, becomes accessible.

Figure 26 illustrates a table where the Amount field (column) is defined as a sum field in the AccountNo + Date key. This enables the DBMS to automatically maintain the accumulated sum of the column. Every time a change is made to a field in the column, the accumulated values are updated.

To the right of the table is shown an area in the database where the

50040

50020

50000

50000

50020

AccountNo Text Amount

100

200

300

400

500

(sum field)

60

210

300

90

Date

100

300

1000

1500

600

Accumulatedsum

02-01-96

01-25-96

01-02-96

01-01-96

01-04-96

A table sorted by AccountNo + Date:

Calculation Filter:

=50020

400

600

1000

300

01-25-96

01-04-96

300

Used in computation for the Calculated field:

50020

50020

Sum of Amount columnin specified range: 1000 - 300 = 700

Figure 26. A table withsumfields, and the same

table when a calculationfilter is applied

Page 202: Guide to the Navision Al Dbms

The NAVISION DBMS 198

accumulated sums for the Amount column are kept. In figure 26, the third field in the column holding the accumulated sum, contains the value 600, because the first three Amount values are 100, 200 and 300, respectively - a total of 600. The fourth virtual field contains 1000, the total of the first four values in the Amount column, and so on. If the table contained a second sumfield, its values would be accumulated in the same way.

What advantages do sumfields offer? They allow fast calculation of sums of columns to be performed and shown via Calculated fields. Let us say you want the sum of all the values in the Amount fields. In a conventional system, the DBMS is forced to access every record and add each value in the field Amount, a very time-consuming operation in a database with thousands of records. Here, the DBMS only needs to access the final field, where the sum of all the Amount fields is always maintained.

Operations with sumfields are equally fast when calculation filters are applied. The second table in figure 26 shows a group of records selected by using a calculation filter on the AccountNo. field. Two records fulfils the conditions of the calculation filter. Only two accesses are needed to sum Amount for these records: one acces to get the accumulated sum associated to the last record before the specified range, and one access to get the accumulated sum associated to the last record in the specified range .

The value 300 is subtracted from the value 1000 to produce the correct sum (700). No matter the number of records in the selected range, the system will always only need to perform two accesses in order to compute the desired sum.

The time used to maintain the accumulated sum for sum fields is negligible due to a special index structure used in the DBMS.