Qubik LavaStream

Language Reference





Table of Contents


 

Introduction

Manual Scope and Target Audience

Using This Reference

System Requirements

Reference Manual Structure

Language Basics

Program Structuring Mechanisms

Database Interfaces

Text and Structure Interfaces

Programming Environment

LavaStream Syntax

LavaStream Functions

LavaStream Examples

 

Language Basics

Abstract

Intent and design of the language

Why not Object Code?

Omission of Pointers

Language Elements

Constants

Basic Types

Assignment

String Manipulation

Concatenation

Declaring a constant

String assignment

Parameter construction and function returns

Substrings (Slicing)

String search

Numeric formatting

XML formatting

Compound Types

Array types

Variables

Typecasting

General Typecasting

Specific Typecasting (Dates)

Specific Typecasting (Times)

Statements

Assignment

String assignment

Assignments to structures

Assignments from XML data into a structure

Assignment into structures from Lava object row types

Assignments between structures

Element assignment

Assignment between equivalent structures

Assignment between non-equivalent structures

Conditions

Case statements

Loops

Procedure calls

Return statement

Formal Procedure Declaration

Comments

External Function Calls

Built-in Functions

Date and Time functions

Variable functions

Lava Database functions

ODBC Database functions

String Functions

Text output and formatting functions

Text file functions

Windows related functions

 

Program Structuring Mechanisms

Procedures

Procedure Declaration

Functions

Modules

Projects

Import Mechanism

Inter-module Imports

Inter-project Imports

 

Database Interfaces

Lava Server Interface

SQL Interface

Row-level Interface

Row-Level Seek

Lava Interface Selection

Error checking

ODBC Interface

Connecting to ODBC database servers

SQL Interface

Result Row Access

Row Insertion

Row Updates

Closing ODBC connections

 

Text File and Structure Interfaces

Text File Interface

Writing Text Files

Reading Text Files

Completing File I/O

XML Interface

XML Import

XML Export

 

Programming Environment

Blueprint Operating Principles

Programming using Qubik Blueprint

Graphical Object Management

Creating Nodes

LavaStream Projects

LavaStream Modules

Editing and Compiling LavaStream Modules

Module List

Procedure List

Compile Button

Dictionary Definition

Table Definition

Column Definition

Definition of Relations

Generating a Dictionary

Creating Data Tables on a Lava Server

Integrating LavaStream with a Dictionary Schema

Testing using LavaStream Elements

Adjusting the Elements Mount Parameters

Running in Exclusive Mount

Executing a LavaStream Procedure

Selecting a LavaStream Procedure for execution

Viewing Output

Debugging LavaStream

Examine Variables

Variables

Arrays

Structures

Setting Breakpoints

Unconditional

Disabled

Conditional

Executing the Code

Step Over - F10

Step Into - F11

Step Out

Go to Breakpoint - F5

Viewing Output

Exit the Debugger

 

LavaStream Syntax

Formal Syntax

 

LavaStream Functions

Date and Time functions

Date

DateFormat

Day

Hour

Minute

Month

Second

TimeFormat

Year

Time

Datetime

MsDate

Variable functions

BITAND

BITOR

BITXOR

Clear

Dec

Even

Inc

Entier

Length

Odd

Round

Abs

String functions

Char

IPfromString

Lower

Ord

ReplaceChar

Slicing

StringFromIP

StringPos

TrimAll

TrimLeft

TrimRight

Upper

Length

Lava Database functions

AutoCommit

Clear

ColumnLabel

ColumnLength

Commit

Createtable

DropIndex

Droptable

FindClose

FindColumn

FindNext

FindRow

FindTable

FreeRow

GetColumn

LavaError

LavaStatus

OpenSession

RenameTable

ReserveRows

Rollback

SetSession

Session

SetColumn

Sql

Tablecolumns

TableName

Tablerows

Translate

Truncate

ODBC Database functions

ODBC_Close

ODBC_Connect

ODBC_Sql

ODBC_Add

ODBC_Update

Text Output and Formatting Functions

Output

Format

XmlHeader

XmlRowdata

XmlFooter

Text file functions

Createfile

Writefile

WritefileNL

Readfile

Spacefile

Closefile

Appendfile

Setfilepos

Setpath

Generic file functions

FindFile

NextFile

 

FindFolder

NextFolder

WinFileCopy

WinFileDelete

WinFileMove

WinFileRename

ReadMemFile

FreeMemFile

ServerFetchFile

ServerPutFile

WriteMemFile

Window Related Functions

Message

Miscellaneous functions

Exec

WinFormatMessage

WinGetLastError

CreateNode

NodePath

ResolvePath

Sleep

SendMail

SetDecimals

Thread

WriteLog

 

Apache Configuration and Testing

Installing Apache

Installing under Windows XP or Windows Server 2003 (Windows 5.1 / 5.2)

Installing under Windows Vista

Apache Configuration

Using the Qubik Apache Install

Manual Apache Configuration

Apache Configuration File

Lava Apache Module

Lava ODBC Driver

Lava Javascript Library

Setting up the Apache Lava Client

Logging

LogLevel

Server

ClientPath

User

Password

Testing with Apache

 

FormatX - Styles and Attributes

 

LavaStream Examples

Coding Techniques

Very Simple Program

Temporary Table as Array Replacement

Windows Programming

Message Box

Lava Database Access

Simple Loop on Lava Table

ODBC Database Access

Retrieving ODBC Data

XML Interfacing

Simple XML Output

Basic XML input

XML List Output




List of IllustrationsB lueprint Desktop

Node Selection Button

Blueprint Editor

Dictionary Example

Dictionary Table Properties

Blueprint Relation Tool

Table Relation Properties

Invoking the Debugger

LavaStream Debugger

Debugger B reakpoints

Debugging Output

LavaStream Elements Interface


















Introduction


Manual Scope and Target Audience


This reference manual covers the usage of and programming using the LavaStream programming language.


This manual is targeted at serious and casual programmers and database users who wish to do one or more of the following :

 

            Write WebServer routines to satisfy Web based applications using a Lava Server database through the WebLava interface

            Write data porting applications to retrieve information from an ODBC database source and place potentially translated data in a Lava Server database

            Write, modify or enhance dictionary template procedures for generating data dictionary related routines or program modules

            Write, modify or enhance window designer procedures for generating form-based routines or program modules

            Create or maintain stored procedures used in a Lava Server or Satellite database


Topics covered include :

 

            Language familiarization

            Programming principles

            Basic use of programming environments (Qubik Blueprint and LavaStream Elements)

            External interfaces (ODBC and XML)

            Language Syntax


Using This Reference


This PDF document is extensively hyperlinked. In order to derive the best usage from this document, note that the Acrobat PDF reader has a “back” button (just like a browser) located in the toolbar, which looks like this :

qubiklavastreamlanguagereference.gif

After following a hyperlink (any blue underlined text) by left-clicking on the hyperlink with your mouse, clicking the “back” button will return you to the hyperlink just accessed. The “back” button will work through multiple levels of links.


The “back” option can also be found in the mouse right-click pop-up menu, named “Go to Previous View”.


Note that as of Acrobat 6, the “back” option is no longer presented in the pop-up menu, and the toolbar looks slightly different :

qubiklavastreamlanguagereference1.gif

 



Also, the toolbar is not displayed by default, and must be activated in the Toolbar options as follows :

qubiklavastreamlanguagereference2.gif

 

There is a keyboard shortcut for the Previous View function, which is Alt+Left Arrow


In Acrobat 8, “Previous view” is once again available in the pop-up menu, and the toolbar now looks as follows:

qubiklavastreamlanguagereference3.gif

 


To enable this toolbar option, go to “More tools” in the pop-up menu when right-clicking in the toolbar area, and select “Previous View” from the Page Navigation Toolbar.


System Requirements


LavaStream requires access to a Qubik Lava Server database for operation. The LavaStream Engine runs on any Windows workstation or server release from Windows XP / Windows 2003 onward. Browser-based applications can be run on any workstation supporting Firefox (revision 2 or later), or Internet Explorer (revision 6 or later). Apache 2.2 or later is the only supported Web server.



Reference Manual Structure


The manual is divided into a number of sections, each of which addresses a specific topic.


Language Basics

A description of the syntax and semantics of the LavaStream language. Information is provided on the design and implementation of the LavaStream system.


Program Structuring Mechanisms

Information on the hierarchical structure of a LavaStream project, including project, module and procedure mechanisms


Database Interfaces

A description of the integration of LavaStream with the Lava database as well as information on the ODBC connectivity presented in LavaStream.


Text and Structure Interfaces

Specification of the available techniques for constructing textual and XML output through the LavaStream text functions


Programming Environment

A brief description of the Blueprint development environment. For detailed information see the Qubik Blueprint Operation Guide.


LavaStream Syntax

A detailed description of the syntax of the LavaStream language, including a formal definition of the LavaStream syntax


LavaStream Functions

Specification and examples of the built-in functions which extend LavaStream for use in database and browser environments, amongst others.


LavaStream Examples

A set of worked programming examples which illustrate the use of several LavaStream techniques and functions.



Language Basics


This chapter addresses the basic aspects of the LavaStream language. Programmers not familiar with Pascal, Modula-2 or Oberon should read through this chapter to gain familiarity with the structure of the language.


Abstract


LavaStream is an interpreted language tightly integrated with the Lava Database.


Close integration with the Apache Web server allows LavaStream programs to be triggered from a Web browser client to respond to complex data-driven page formatting and data output requests.


As LavaStream programs are stored in the Lava database, they may be used as stored procedures and may be triggered remotely or locally to perform complex data manipulation or validation tasks.


Due to integrated ODBC functionality, LavaStream may be used to extract data from third-party databases, and potentially to reformat, process and re-insert data, potentially into a different database than the originating data. Using the automatic distribution facilities of the Lava database coupled with the ability to run LavaStream programs on Lava Satellite servers, data may be collected, stored, processed and inserted to or from databases residing on different continents, if required.


Coupled to the ability of Lava Satellite servers to link to a Lava Primary server across an internet link, LavaStream presents the ability to run browser-based thin client applications on remote sites using their own Apache Web server, thus attaining local area network (LAN) speeds in an application which stores and retrieves its centralised data on a remote site. This allows fast response and processing as well as bandwidth independence while retaining centralised data storage.


As LavaStream programs are automatically distributed across a Lava database network to all Lava Satellite servers, LavaStream program updates performed at the central server automatically deploy to all satellite sites within seconds. This eliminates complex installation and update procedures, as all linked sites immediately upgrade to the latest revision of the software.


LavaStream is engineered to be extremely fast and efficient. Even a moderate Web server running Apache and Lavastream will be capable of serving thousands of browser clients - due to the tight integration of LavaStream with the Lava database, and the distributed architecture used in the Lava Server and the LavaStream client, typical requests from browser client applications are serviced within a few milliseconds, allowing very large numbers of browser clients to be served without processor or bandwidth limits being reached. Coupled to the ability to decentralize servers using a Lava Satellite network, it becomes possible to configure business application networks serving tens of thousands of browser clients with almost insignificant hardware cost.


When using a Lava Satellite network with localised Apache Web servers to decentralize client load, the bandwidth load on the network to the central Lava and Apache servers is decreased dramatically. Transaction loads running into hundreds of transactions per second can be processed with a total bandwidth demand from decentralised Satellite servers of no more than 64 kilobit per second, resulting in the available bandwidth to the central Web server being freed up for other purposes.


Intent and design of the language


LavaStream is intended to provide a powerful, easy to use interface between the Lava database and external systems. Specifically, interfaces are provided to Apache for Internet interface, ODBC interface for access to third-party databases, text file interface for creation of text files, and XML interface for import and export of XML structure sets.


Extensive and highly functional programs can be written using LavaStream, but it must be understood that LavaStream is not intended to be a completely general-purpose programming language. Although it is certainly possible to perform a very wide range of tasks using LavaStream, the primary intent of the system is to provide an interface to databases, and most specifically to the Lava Server database.


The primary targets of LavaStream are :

            Programming WebServer-based systems using a browser as the client interface

            Writing or extending code generation routines for the Blueprint Dictionary system

            Writing or extending code generation routines for the Blueprint Browser Window system

            Writing stored procedures for a Lava Server database


The design of the language is aimed at providing a means of writing programs in a way which allows the programmer the maximum in flexibility while retaining structural integrity, and ensuring that the language is legible and maintainable.


Basic language syntax is patterned on Oberon, a language very similar to Pascal in syntax. The choice of Oberon as a starting point is due in part to the small language definition, providing a very quick learning curve, and the high legibility of Oberon programs, resulting in easy maintenance.


A few modifications to the Oberon language have been adopted.

 

1.           Only linear (non-object) code is supported. This allows the language - and therefore the runtime - to be simpler, and hence also smaller and faster. Although object code does have advantages in certain forms of applications, this is more than offset by the tight integration of LavaStream with the Lava database, which presents a functional enhancement in some cases greater than would have been provided through object code.

2.           Automatic typecasting is supported. This violation of the strict typecasting in Oberon was decided due to the demands for rapid development of software, and the corresponding easing of requirements on the programmer to achieve a given aim.

3.           Some variable types were eliminated. Since LavaStream is a special-purpose language, several variable types and constructs (such as unions, for example) are not considered mandatory. In general, however, all the important data types and structures are supported.

4.           Return of compound types was included. This renders several complex operations possible with greater ease than in Oberon.

5.           Procedure-level declaration of constants and types is disallowed. There is little benefit to procedure-level scoped constants and types, with significant extra complication in both compiler and runtime engine, and thus it was decided to eliminate this option.

6.           Nested procedures are not supported. This would complicate the runtime engine to a significant degree without a comparable degree of improvement in functional scope.


Why not Object Code?


We would not argue against the statement that there is a place for object code in certain applications. However, in many (if not most) applications where object code is appropriate or valuable, the most important function served by the class / object mechanism is the storage and retrieval of runtime data relating to the operation of the software. The actual method usage in many cases is subservient to the convenience of having the built-in object linkage provide for transient storage of data (in most environments lost on program exit) allowing complex linked structures to be constructed, traversed and retrieved during execution.


In the LavaStream environment, the designer / programmer has an entire database at their disposal, including the ability to create any number of virtual tables (defined and accessed entirely in memory) with very little effort - certainly no more effort than that required to define and construct a class / object system. As a result, the requirement for storing transient data is fully addressed without the requirement for objects, while the virtual table mechanism is both faster and more versatile than a linked object implementation. In addition, the ability to define permanent storage just as easily allows vastly more functionality than provided by a object system. In a LavaStream environment, due to the distributed nature of the Lava database, physical (permanent) tables operate just as fast as virtual tables under the majority of circumstances, giving the best of all scenarios.


The only omission, therefore, is the method mechanism - which is only really of greater value than a conventional function call when overloading allows different methods to be selected depending on the type of the object processed. It is our viewpoint that this practice - powerful as it may be - is adverse to good code maintenance, as it obfuscates the functionality of the code by rendering the actual function executed through the method non-obvious. For this reason, this sole advantage of object systems over the LavaStream implementation is seen not as an advantage at all, but rather as a maintenance detriment. As programs are written once and maintained many times, the maintenance disadvantage outweighs the functionality represented by overloading very easily. Given this deduction, it was an easy and logical decision to eliminate class / object functionality entirely in order to improve the overall maintainability of the system.


In summary, the true advantages of object systems, primarily represented by transient data storage, are easily compensated through the direct integration of LavaStream with the Lava database. Inheritance and overloading are viewed as of dubious value in the LavaStream domain (that being database and human interface centric applications) and are therefore discounted. The advantages of a small, fast, reliable runtime system as implemented in LavaStream outweigh any residual positive aspects of an object system easily. For comparison, the Sun Java runtime is more than 6 Mb in size. The LavaStream runtime is approximately one tenth of that size, while the effective functionality presented by the two systems - although fairly different - is very similar in total scope. As a second example, the PHP runtime is over 12 Mb in size, and the total functionality presented in PHP is significantly less than that included in LavaStream, while LavaStream execution (in exactly the same domain) is significantly faster.


Omission of Pointers


The specification and use of pointers and pointer-type variables has intentionally been omitted in LavaStream. Although there is no doubt that pointers are extremely flexible, and provide a very powerful mechanism for abstraction when used correctly and carefully, it is equally true that pointers provide many possibilities for memory corruption and access violation.


In terms of the requirement to provide a run-time environment which is as stable and reliable as possible, while also providing the programmer with a language which promotes stable and reliable code, it is our view that providing pointers in this environment is generally more likely to lead to instability than is the case with other variable types and reference mechanisms.


For this reason, the LavaStream language is defined in such a way that almost any desired result may be obtained without the use of pointers. Procedure parameter declarations provide a by-reference syntax (equivalent to that used in Pascal or Oberon) as follows :


   VAR parameter : INTEGER;


In the above parameter specification, the VAR keyword specifies that the parameter is by reference, in other words modification of the parameter in the called procedure will result in equivalent modification of the nominated actual variable in the calling procedure. The system provides this by reference link without resorting to the use of pointers, and it is not possible to cause memory corruption in the called procedure through any manipulation of the parameter.


Where a particular result is desired which cannot be envisaged without the use of pointers, the advanced programmer may simply resort to calling an externally defined procedure.


See also

Formal Procedure Declaration, External Function Calls


Language Elements


This section describes the basic elements of the LavaStream language. For further information on use and implementation of LavaStream code, see the syntax and examples sections.


Constants


Constants are supported only at module level - procedure constants are not provided.


As with variables, constants permit mixing of types - the result of a constant construction will be a value of the most sensible type given the nature of the constant definition.


Constant definitions such as those following are supported :

 

     PI         =    3.141592E00;

     Name       =    ‘Jones’;


Complex constants may be constructed :

 

     Code       =    3.5 * 2 / 8.7;

     Password   =    ‘aBc’ & 22/7 & ‘xag’;


Character codes defined in hex may be used :

 

     NEWLINE    =    0DX & 0AX;

     Line       =    ‘Start’ & 09X & ‘after tab character’;



Basic Types


LavaStream supports a sufficiently diverse set of basic variable types to allow programming of most algorithmic and data processing requirements.

 

DATE                  A julian date representation, with the earliest being 1 Jan 300 CE

TIME                   A numeric representation of time with 0 representing midnight, and a non-zero number representing the count of milliseconds since midnight

DATETIME        A combined date and time representation, with the integer portion being the julian date, and the fractional portion being a count of milliseconds since midnight, divided by 100,000,000

BOOLEAN         A byte-sized variable with allowable values TRUE and FALSE only. Internally, TRUE is equivalent to 1 and FALSE is equivalent to 0

BYTE                  An unsigned byte-wide variable, which may contain one character or a numeric unsigned value of maximum 255

SHORT               A signed, 2-byte integer

INTEGER           A signed, 4-byte integer

IP                         Equivalent to a 4-byte integer, but specifically intended to store IP (internet protocol) addresses.

QUAD                 An unsigned, 8-byte integer

SHORTFLOAT  A 4-byte floating point number

FLOAT               An 8-byte floating point number

STRING              A string variable. The length of the variable is generally unspecified, with the exception of ROWTYPE compound variables (see below). The variable will automatically extend to any size to accommodate required input

TABLE               A variable intended to store table identifiers, for example resulting from SQL select statements (see Lava functions below)

ROWTYPE         A compound type (structure) - see below

LAVA                 A keyword used to define Lava Server table structures - see compound types below

Assignment


Assignment between variables or from a function procedure to a variable is accomplished through the same syntax as with Pascal or Oberon :


   Var1 := Var2;


Most variables may be assigned to one another, with the exception that complex variables (such as arrays or structures) may not be assigned to simple variables (such as integers or floats) or vice versa. A partial exception to the first rule is that strings may be assigned to simple types, and the result is the interpretation of the content of the string in terms of the type of the target variable. For example, assigning a string which contains the value “12.34" into a float variable will result in the float variable containing the float value 12.34. Similar appropriate results will be produced with assignment into integers or booleans. Simple types may also be assigned into strings, with the resultant string value being the closest match to the variable value (for example, assigning a boolean into a string will have the results “TRUE” or “FALSE”).


In general, arrays of equivalent type may be assigned to one another (regardless of specific size issues) and structures which are sufficiently equivalent to produce sensible assignment may be assigned - the LavaStream runtime will produce the best possible results given the most applicable match between source and target variables.


Assignment of function procedure results into a variable (either built-in functions or user declared) operates on the same principle as variable assignment, for example :


   DateVar := DATE();


The casting rules are identical to those for variables, including functions which return string variables.


See also

Typecasting


String Manipulation


Due to the requirements for complex string processing, especially in the Web domain, strings are given special attention in LavaStream. The following facilities are supported :


Concatenation

Concatenation is supported in every possible syntactical point where a string may be used. The following examples illustrate usage of concatenation

 

Declaring a constant

     Password = ‘aBc’ & (34 / 7) & ‘xxx’;


Note in the above example the brackets around the calculation, 34 / 7. Without these brackets, the concatenation operator (&) will take precedence over the division (/) and will execute first, yielding “aBc34". The division will execute afterward, resulting in 0.0 (since the first string will evaluate to numeric 0).

 

String assignment

     StringVar := StringVar & 23.33 & (FloatVar / 2) & StringVar2;

 

Parameter construction and function returns

     StringVar := FuncProc1(StringVar & ‘abc’ & FloatVar) & ‘endofstring’;


Substrings (Slicing)

The most efficient and unambiguous way to extract substrings from a string variable is through a technique known as slicing. This is illustrated in the following example


If StringVar contains the string ‘abcdefgh’, the following slice instruction

     NewSubString := StringVar[3..5];

yields the string ‘def’, whereas

     NewSubString := StringVar[0..3];

yields the string ‘abcd’.


Variables or any other form of numeric derivation may be used as parameters in the slice, for example

     NewSubString := StringVar[IntegerVar1..IntegerVar2];


String search

String searching is supported through the function STRINGPOS, as illustrated below

     Charpos := STRINGPOS(‘abcdefg’, ‘bc’);

which yields the result 1 - position 0 is the first character in the string.


The STRINGPOS function may be used in an alternative mode, when the starting position of the search must be stipluated.

     Charpos := STRINGPOS(‘abcabcdefgh’, ‘bc’, 2);

which yields the result 4, as the starting position of the search is position 2, thereby eliminating the first occurrence of ‘bc’ as a result.


Numeric formatting

Several quantities are represented numerically in LavaStream, such as dates (in Julian form) and times (in milliseconds since midnight), therefore requiring formatting into string form for output purposes. To support this, the function FORMAT is provided, which allows various numerical representations to be converted to corresponding string representations. Some examples follow - for more detailed information on the FORMAT procedure, see the LavaStream Syntax chapter.


CONST

   DateStyle = FormatX.FORMAT_P_DATE;

   DateFormat = FormatX.FORMAT_S_DATE_9; (* selected date format is yyyy/mm/dd *)

   TimeStyle = FormatX.FORMAT_P_TIME;

   TimeFormat = FormatX.FORMAT_S_TIME_2; (* selected time format is HH.mm.ss *)


   OUTPUT(FORMAT(DATE(), DateStyle, DateFormat));

Built-in function DATE returns the current date


   OUTPUT(FORMAT(TIME(), TimeStyle, TimeFormat));

Built-in function TIME returns the current time.


Many other possibilities exist, ranging from a variety of date and time formats (listed in the supplied module FormatX, which specifies the constants equating to various formats and styles) through numeric formats such as currency and percentage, through floating point formats.


XML formatting

In order to support XML interfaces, both to client-side JavaScript as well as other external interfaces, LavaStream supports a set of XML output formatting procedures. An example is provided below.


The following type definition provides a structure for XML output :

TYPE

   FormType = ROWTYPE

      customer : STRING[100];

      address : STRING[100];

      country : STRING[100];

   END;


The code below will construct XML output in the text stream :


   Form.customer := 'John Smith';

   Form.address := '238 Stream Street, London';

   Form.country := 'England';

   Form.ROWID := 234;   (* optional *)

   OUTPUT(XMLHEADER(TRUE, 'items'));

   OUTPUT(XMLROWDATA('formdata', Form));

   OUTPUT(XMLFOOTER('items'));

In the above code, the TRUE specification in the XMLHEADER parameters stipulates that the ?xml version specification is output in the header.


The following XML will be produced :

<?xml version="1.0" encoding="utf-8" ?>

<items>

  <formdata ROWID=”234">

    <customer>John Smith</customer>

    <address>238 Stream Streat, London</address>

    <country>England</country>

  </formdata>

</items>

Note the ROWID attribute in the above XML - this is produced to allow interface to client forms, so that the database row information is preserved. If the ROWID attribute to the form is zero, this information is omitted.


See also

Specific Typecasting (Dates), Assignments to structures


Compound Types


LavaStream supports two forms of compound structure types.


The first is used to define structure types compliant with Lava Server tables (either user tables or system tables to which sufficient access privilege exists).


This definition takes the form

 

     TableVar   :    LAVA.EVENT.Sys_Event.TYPE;


In this definition, the prefix LAVA qualifies the type as a lava table definition. The EVENT qualifier specifies the Event Lava database schema. The identifier Sys_Event qualifies the Sys_Event table in the Event schema. The suffix TYPE specifies that the variable acquires the row type of this table.


The second compound type is used for the definition of user-defined row types. An example follows


TYPE

   FormType = ROWTYPE

      customer : STRING[50];

      address : STRING[100];

      ID : INTEGER;

      district : STRING[60];

   END;


The preceding definition in the TYPE section defines a compound type, called FormType. This specifies a row type comprising three string variables of specified length (50, 100 and 60 bytes respectively) and a 4-byte integer field. Note that in contrast with basic string variables (which are specified without length) string variables in row types are specified with a given length. This is necessary as row types may be used to create tables in the database, and specific length of fields defining table columns is therefore required.


Row types may be used to define variables or parameters, as follows


   FormData : FormType;


Rules of assignment of row types are defined as dictated by logic.

            Compound variables of differing row types may be assigned to one another provided the number of fields in each row type is the same. Fields are typecast on a field for field basis.

            Table rows may be assigned from a Lava data table into a row type variable provided the number of fields in the row type is the same as the number of columns in the table. Fields are typecast on a column-to-field basis.

            Variables of a given row type may be assigned into a row of a Lava data table provided that the number of fields in the row type is the same as the number of columns in the table. Fields are typecast on a field-to-column basis.


Array types


Arrays of simple types


Arrays of several simple types are fully supported in LavaStream. These include arrays of String, Boolean, Integer, Float and Quad values. Arrays of character are supported through the STRING built-in type. Only single-dimensional arrays are supported in the current release.


Arrays in LavaStream are indexed from index 0 (0-based).


In order to present the most usable definition of an array variable, LavaStream does not require the specification of an array bound. The following example illustrates the definition of an array :


VAR

   ArrayVar : ARRAY OF INTEGER;


In the case of string arrays, the length of the string must be specified, as in the following example :


   ArrayVar2 : ARRAY OF STRING[100];




Note that in this example, no bound (limit) to the array size is specified. LavaStream will allocate memory as required, to a limit of 100,000 elements. The array will naturally resize as required, whenever an element is written into the array as follows :


   ArrayVar[230] := 99;

In the above example, regardless of the previous size of the array, the assignment as specified will automatically enlarge the array to 230 elements (actually 231, since element 0 is a valid array element).


Although reading from a nonexisting element in an array will not cause run-time failure, it will return 0.


Arrays may be passed to procedures as parameters both using by reference (VAR) or by value parameters. Arrays may also be assigned to other array variables, provided that the type of the array (Integer, Boolean..) is the same for both array variables. In the case of string array variables, the length of the string must also be the same.


Arrays may also be returned as the return type of a function-type procedure. The same provisions apply to returned arrays as for other array assignments.


Arrays of complex types


Arrays of structures are not directly supported in LavaStream in a conventional programming sense. In order to simultaneously reduce the complexity of the language and eliminate the problems associated with array size limits, LavaStream uses tight integration with the Lava database to support infinitely extensible arrays in the form of Lava data tables (virtual or physical). These are addressed - both for writing and reading - with conventional array syntax, and writes to arbitrary array indices are supported through automatic extension of the data table.


See the example Temporary Table as Array Replacement for an illustration of table creation and access.



Variables


Both module-level and procedure-level variables are provided for. Conventional rules of scope apply to visibility and persistence of variables.


Variables may be declared of any basic variable type, or of user-defined row types. Variables may also be declared of Lava Table types, which result in a variable of the same type as the nominated table column definition.


Basic data types behave as per conventional rules for fixed-length variables. However, string type variables in LavaStream behave differently than those in conventional formal languages. String variables are automatically extended to accept assignment of arbitrary length, in order to accommodate lengthy, complex composition of (for example) web pages. Arrays of simple types behave in essence the same as string variables - assignment to a given index in the array ensures that the array is at least of sufficient size to store the nominated index.


Typecasting


General Typecasting


In order to provide a programming environment which allows sufficient freedom to code without impediment, any sensible form of typecasting between variable types is supported implicitly. In other words, even variables such as strings and integers may be assigned to one another freely.


It is understood that in a weakly typed language such as this, certain forms of type violations which may constitute programming errors would escape detection. In programming, much of design is based on compromise, and given the intent of this language it was felt that a weakly typed model was the more appropriate one.


For example, the following line of code

   OUTPUT(‘<td>’ & FormData.InvoiceTotal & ‘</td>’);


would be considerably less convenient to code if automatic typecasting between a numeric value (FormData.InvoiceTotal) and the string type of the parameter to OUTPUT() were not permitted.


Thus, all typecasting which can be sensibly deduced is supported without warning or error. It is, therefore, the responsibility of the programmer to ensure that the results of such variable typecasting is desirable.


In the same manner as the above, automatic typecasting is supported between a number of basic types :


 

Target Type

Permissible Source Types

Comments

INTEGER

BOOLEAN

FLOAT

INTEGER

QUAD

STRING

Where the target type does not provide for the capacity of the source type, truncation or elimination of detail may occur.


String assignment into numerical types requires a valid numerical formatted string for successful conversion.

FLOAT

BOOLEAN

FLOAT

INTEGER

QUAD

STRING

Same constraints as above 

BOOLEAN

BOOLEAN

FLOAT

INTEGER

QUAD

STRING

A boolean target interprets the source as TRUE if numerically non-0, and FALSE if numerically 0.


For a string source, the strings TRUE and FALSE are specifically tested.

QUAD

BOOLEAN

FLOAT

INTEGER

QUAD

STRING

Assignment into Quad variables typically addresses only the Low part of the variable, with the exception of very large float values and other Quad variables.

STRING

BOOLEAN

FLOAT

INTEGER

QUAD

STRING

Conversion from boolean value to string yields the strings TRUE or FALSE as result.


Note that in the above table only root types have been listed. Implicitly, if conversion is supported between INTEGER and FLOAT, then conversion is also supported between SHORT and SHORTFLOAT. In cases where the assignment target is smaller than the source, the possibility of overflow exists which will cause the target variable in the assignment to have an invalid or unrelated value after the assignment has been performed.


Specific Typecasting (Dates)


In order to allow conversion from textual dates to Julian dates, the system supports assignment from strings into variables of type DATE with analysis of the string to deduce the date implied.


In order to provide for different source date formats, the built-in function DATEFORMAT is provided, which accepts the following date formats :


   FORMAT_S_DATE_1 - = 1; (* dd/mm/yy *)

   FORMAT_S_DATE_2 - = 2; (* dd/mm/yyyy *)

   FORMAT_S_DATE_3 - = 3; (* mm/dd/yy *)

   FORMAT_S_DATE_4 - = 4; (* mm/dd/yyyy *)

   FORMAT_S_DATE_9 - = 9; (* yyyy/mm/dd *)


Once a default date format has been set, if a string or string variable is assigned into a DATE- type variable, the string is interpreted as a date in the given format. The date is converted into a Julian-format date and assigned into the date variable.


Specific Typecasting (Times)


tbd


Statements


The following programming statements are supported in LavaStream


Assignment

Assignment in LavaStream, as in Pascal or Oberon, uses a more formal assignment symbol in order to distinguish assignment from equality comparison (A = B).


   Var1 := Var2;


Assignment into defined variables is supported from :

 

            Other variables either of the same type or with allowable typecasting

            Functions returning an appropriate type

            Rows from Lava tables where the variable is of an appropriate row type or Lava row type

Automatic typecasting on a variable or field basis is applied on assignment.


String assignment


String assignment is extended in several ways, given the particular requirements of string variables.


Firstly, concatenation is supported during assignment :


   StringA := StringB & ‘abc’ & StringC;


In the above assignment, both a literal string (‘abc’) and a variable (StringC) are concatenated to the base assignment (StringB).


Secondly, automatic type conversion is performed if the source variable is not a string. In the example below, if VarA is a float variable containing the value 23.567, the assignment


   StringA := VarA;


will result in the string value ‘23.567' in the variable StringA.


Thirdly, string slicing is supported in both the left and right-hand of the assignment :


Given the following starting values for two variables :

 

              StringA                :             ‘0123456789'

              StringB                :             ‘ABCDEFG’


The assignements as below would yield results as stipulated :


   StringA := StringB[2..4];

              ‘CDE’


   StringA[3..5] := StringB;

              ‘012ABCDEFG6789'

Note : The entire StringB is inserted into StringA, replacing segment 3..5


   StringA[3..4] := StringB[0..3];

              ‘012ABCD6789'


Also :


   StringA[4] := StringB[2];

              ‘0123C56789'


   StringA[4] := StringB;

              ‘0123A56789'

Note : Since the target specification stipulates a single character replacement (not a slice) this is exactly what happens - as no index or slice is specified for StringB, the inserted character defaults to the first character.


   StringA[4..4] := StringB;

              ‘0123ABCDEFG56789'

Note : In this case, the target specifies a slice - although this slice consists of only one character, the replacement allows any number of characters to replace the nominated slice.


All of the above may also be combined with concatenation in the right hand side.


Assignments to structures


Two extended assignment mechanisms are supported when assigning to structures.


The first is assignment of XML data into a structure. The second is assignment from Lava row types into an appropriately defined Row Type structure.

 

Assignments from XML data into a structure


Provided that the row type structure is correctly defined, XML data containing tags matching the structure elements will be assigned directly into the structure. For example, in the source code shown below, the assignment of the XML data as specified will result in the elements of the structure being assigned as follows :


Invoice_id : 2

Product_id : 23

LicenceQty : 999

Promotion_id : 0

Discount : 0.0

Amount : 999.0

bVatable : boolean FALSE

Licence_id : 0


Note that elements are matched with the tag name - the position (sequence) in the structure or the XML does not matter.


TYPE

   DetailType = ROWTYPE

      Invoice_id : LONGINT;

      Product_id : LONGINT;

      LicenceQty : LONGINT;

      Promotion_id : LONGINT;

      Discount : LONGREAL;

      Amount : LONGREAL;

      bVatable : BOOLEAN;

      Licence_id : LONGINT;

 

   END;

 

PROCEDURE TestAssign;

VAR

   DetailStruc : DetailType;

BEGIN

   DetailStruc := '<items> ' &

                     '<formdata > ' &

                        '<Invoice_id>2</Invoice_id> ' &

                        '<Product_id>23</Product_id> ' &

                        '<LicenceQty>999</LicenceQty> ' &

                        '<Promotion_id>0</Promotion_id> ' &

                        '<Discount> 0.00</Discount> ' &

                        '<Amount> 999.00</Amount> ' &

                        '<bVatable>FALSE</bVatable> ' &

                        '<Licence_id>0</Licence_id> ' &

                     '</formdata> ' &

                   '</items>';

END TestAssign;


 

Assignment into structures from Lava object row types


Lava object row types may be assigned into structures, provided that the structure is appropriately defined.

In the following example, assuming that the Lava table has an identical definition to that of the row type, the assignment will occur on an element-by-element basis.


Table rows are assigned into structures in a strictly sequential manner - the first column in the table is assigned to the first element of the structure, and so on until the number of columns in the table has been exhausted or the structure runs out of elements.



TYPE

   DetailType = ROWTYPE

      Invoice_id : LONGINT;

      Product_id : LONGINT;

      LicenceQty : LONGINT;

      Promotion_id : LONGINT;

      Discount : LONGREAL;

      Amount : LONGREAL;

      bVatable : BOOLEAN;

      Licence_id : LONGINT;

 

   END;

 

PROCEDURE TestAssign(pRow : INTEGER);

VAR

   DetailStruc : DetailType;

BEGIN

   DetailStruc := LAVA.Accounts.InvoiceDetail[pRow];

END TestAssign;



Assignments between structures


Several forms of assignment between structure variables are supported.

 

Element assignment

Elements in structures may be assigned to one another. In this form, the normal rules of casting apply.


   Struc1.element1 := Struc2.element3;

 

Assignment between equivalent structures


Given the following variable definition :


VAR

   DetailStruc1 : DetailType;

   DetailStruc2 : DetailType;


the following assignment may be performed :


   DetailStruc1 := DetailStruc2;


In the case where the two structures are of the same type, the assignment is performed element-by-element with the first element of the source variable assigned to the first element of the target variable, and so on. Normal assignment rules apply to each element.

 

Assignment between non-equivalent structures


Where the variables are of different types, assignment may still be performed. Given the code segment below, the assignment of Var2 into Var1 will assign :


Var2.FormRow_id to Var1.FormRow_id

Var2.UnitCost to Var1.UnitCost

No assignment will be done to Var1.First.


The elements are assigned on a like-named basis, regardless of individual element type.


Normal casting rules apply to the assignments.


TYPE

   VariableData= ROWTYPE

      First : STRING[100];

      UnitCost : STRING[100];

      FormRow_id : INTEGER;

   END;

 

   VariableSwitch = ROWTYPE

      FormRow_id : INTEGER;

      UnitCost : STRING[100];

   END;

 

PROCEDURE Calc ();

VAR

   Var1 : VariableData;

   Var2 : VariableSwitch;

BEGIN

   Var1 := Var2;

END Calc;


Conditions

Simple and compound conditions are supported according to standard boolean rules. Any comparison results in a boolean value, and thus boolean variables may be used in stead of a comparison, as in the following example


   IF (Quantity > 500) OR bOverflow AND (Total = 33.5) THEN

   END;


Note that in the equal comparison only a single equal sign is used, unlike the double equals (==) used in languages like C.


Block constructs in LavaStream are implicit; in other words the above IF statement automatically commences a block of statements without the requirement for a BEGIN as would be necessary in Pascal. For this reason, the END statement above is mandatory to close the block automatically commenced by the IF.


Case statements

Complex case statements are supported, with two case constructors (range and alternative). The following example shows the basic variants.


   CASE Index OF

   | 33 :

   | Limit :

   | 42 .. 57 :

   | 75, 87, 95 .. 100 :

   ELSE

   END;


Note that in contrast with languages like C, each case strictly contains the executed code. In other words, in the example above, if the value of Index is 33, the code contained between the commencement of case 33 and prior to case Limit will be executed, and the case terminates. No “break” clause is required - only one case clause at maximum can execute. If all specified cases do not apply, and an ELSE clause is provided, the code contained in the ELSE clause will execute.


As with the IF statement above, each case clause implicitly commences a block of code - no BEGIN..END is required.


Loops

Four loop types are supported. These are :

            FOR loops           Loops with a specified counter, increment and limit

            WHILE loops      Loops with a preceding exit condition

            REPEAT loops    Loops with a succeeding exit condition

            Infinite loops       Unbounded loops

For all of the above, two control statements are supported :

CYCLE               skips the remaining statements in the loop and recommences at the start of the loop. Increments and exit conditions still apply.

EXIT                   exits the loop unconditionally.


In all of the above cases, the loop commencement statement automatically commences a block of code which is terminated by the end construct of the loop.


The following examples show basic syntax and application of loop types


   FOR Index := 1 TO 10 DO

   END;

 

   FOR Index := Start TO End * 5 BY 3 DO

   END;

 

   WHILE a = b DO

   END;

 

   REPEAT

   UNTIL a > b;

 

   LOOP

      IF a > b THEN

         EXIT;

      END;

   END;


Procedure calls


Procedure calls are as for Pascal or Oberon when the procedure is local to the module, as follows :


   MyProcedure(Parameter1, Parameter2);


Similarly, function calls are an assignment into a variable :


   LocalVar := MyFunction(Parameter1, Parameter2);


If the procedure or function is not local to the module, the call must be prefixed by the name of the imported module :


   ImportedModule.ForeignProcedure(Parameter1, Parameter2);


As with assignment, it is permissible for the actual parameter (the parameters specified in the call to the procedure) to differ from the formal parameter type (the type of parameter in the definition for the procedure) as long as assignment between the types is permissible and supported.


Return statement


The RETURN statement may be used both in procedures and in function-type procedures (procedures with a declared return type) at any point within the procedure to return to the calling procedure.


In the case of function-type procedures, the returned variable or constant need not be identical to the declared return type for the procedure, as long as casting from the returned type is supported by LavaStream :


   RETURN 0;


will return to the calling procedure and return a value of 0 as the function value.


Formal Procedure Declaration


The declaration of procedures in LavaStream is almost identical to that in Pascal or Oberon, with a few small differences.


PROCEDURE ExampleFunc( pSession_id : INTEGER;

                       VAR pObject_id : INTEGER;

                             pbProfile : BOOLEAN;

                             pSerialPort : STRING

                      ) : INTEGER;


Note that although the above procedure declaration is that of a function (the procedure returns an integer value) the prototype is still declared as PROCEDURE - there is no specific function type; functions are merely procedures which return values. However, this is not to be confused with the declaration of functions in languages such as Javascript where a “function” may return a value or not as the programmer sees fit - in LavaStream a function-type procedure must declare its intention to return a value in the prototype declaration as above, and such a function-type procedure must return a value when terminating, as in :


   RETURN 0;


If a return without a specified return value is coded in a function-type procedure, this is a syntactical error.


Similarly, an untyped procedure (a non-function procedure) may not return a value, and any returns coded in the body of the procedure must be without any return value, as follows :


   RETURN;


If, in a non-function procedure, a return value is specified this is also a syntax error.


Since the value specified in a return for a function-type procedure is identical to an assignment, the rules of automatic typecasting apply (see Typecasting for further details).


With the exception of the pObject_id parameter in the example above, all the parameters will be passed by value. Parameters specified of form VAR are passed by reference.


Parameters which are specified by value form valid local variables in the procedure, and modification to these variables will not reflect on the calling procedure in any way.


Parameters specified as VAR (by reference) are assigned back to the referenced variable in the calling procedure whenever modification occurs. Although this is similar to the effect achieved when declaring a variable as a pointer reference in languages such as C (such as int * pObject for example) the implementation is not exactly the same. LavaStream does not support pointers directly and no pointer arithmetic is supported by the language.


Unlike Oberon, it is permissible to specify a complex return type such as an array or structure, which provides more flexibility and makes it easier to abstract functionality.


See also

Omission of Pointers


Comments


Several forms of comments are supported. Both multi-line and single line comments are provided, and both types allow nesting to arbitrary depth


(* start of multi-line comment

   A := b;

// Single-line comment

End of multi-line comment *)


External Function Calls


Although every effort has been made to provide as comprehensive a programming environment as possible in LavaStream, it is not possible to provide every possible function. For this reason, a mechanism is provided to allow external functions to be called from within LavaStream. Certain restrictions apply, but sufficient flexibility is provided that the majority of functions and parameters may be called easily.


In order to call an external function, this function must first be declared in LavaStream source. An example of such a declaration is provided below.

PROCEDURE [EXTERNAL:MyDLL] ExportFunc( pSession_id : INTEGER;

                                       VAR pObject_id : INTEGER;

                                             pbProfile : BOOLEAN;

                                             pSerialPort : STRINGPOINTER

                                      ) : INTEGER;


In the above example, the attribute [EXTERNAL:MyDLL] specifies that the procedure declaration is for an external function. The MyDLL portion identifies the DLL within which the function is to be found. This DLL must be available to the LavaStream runtime - typically this implies that the DLL must be present in the Windows System32 folder (commonly located at C:\Windows\System32). In addition, any DLLs required by MyDLL must also be present in this folder.


Both by-value and by-reference (VAR) parameters are supported for simple types, but note that STRING parameters are not supported - these cause complications in terms of the length of the string on the stack. Instead, the STRINGPOINTER parameter is provided - this will accept any conventional LavaStream STRING or a string constant, but will define a pointer to the string on the stack which must be accessed as such by the external function. By reference parameters are, in the case of external functions, defined as pointers to the nominated actual variable, and so the programmer must take appropriate care not to cause memory corruption in the external function when accessing these parameters. Note especially that specific storage details about LavaStream variables are intentionally not declared to permit modification to the design of the LavaStream engine without modification to the documentation - for this reason, accessing pointers in the form of by reference parameters in non-standard ways is not advised.


Simple return parameters are supported (integer, boolean, float) but not strings. Similar complications to those described above preclude this option. Pure procedures (no return value) are also supported.


Note that structures are not supported as parameters. LavaStream structures (in the form of ROWTYPE) are not size-specific, and are therefor not usable. Sized structures will be provided for this purpose in a future release of the LavaStream environment.


It is very important to ensure that the procedure declaration in the target function matches the external declaration in LavaStream exactly - if not, the system will undoubtedly corrupt the stack, and probably halt on some form of exception It is not possible for the LavaStream compiler to validate the procedure declaration, and thus the onus of consistency checking is entirely the responsibility of the programmer.


The external function must be defined with the Pascal calling convention - in a language such as C, this implies a function of type __declspec(dllexport) WINAPI (or equivalent). Any appropriate language may be used, such as Borland Pascal or Visual C - note, however, that interface to class-based functions will not be possible. Also, as Java is not a machine language but an interpreted one, functions in Java cannot be called.


Built-in Functions


This section provides a brief list of the built-in functions presented in the LavaStream language. For detail on the functions listed, see the LavaStream Functions chapter as well as the examples provided.


Date and Time functions


Date

Returns the current date in Julian format

DateFormat

Specify the default date format

DateTime

Returns the current date / time

Day

Returns the day of the month for a given Julian date

Hour

Returns the hour for a given Lava-format time

Minute

Returns the minute of the hour for a given Lava-format time

Month

Returns the month for a given Julian date

MsDate

Returns the Julian date from a given Microsoft-format SQL timestamp

Second

Returns the second of the minute from a given Lava-format time

Time

Returns the current time

Year

Returns the year from a given Juilian date



Variable functions


ABS

Returns the absolute value of a value or variable

BITAND

Returns a bitwise and of two variables

BITOR

Returns a bitwise or of two variables

BITXOR

Returns a bitwise xor of two variables

CHAR

Returns the ASCII character representing a given ordinal value

CLEAR

Clears a variable to null values

DEC

Decrements a variable by 1 or a specified amount

ENTIER

Returns the integer part of a numeric variable

Even

Returns true if the given number is even

INC

Increments a variable by 1 or a specified amount

Length

Returns the length of a given string

LOWER

Returns a string in all lowercase

Odd

Returns true if the given number is odd

ORD

Returns the ordinal value of a character

ROUND

Returns the rounded (integer) value of a variable

STRINGPOS

Returns the position in a string of a string fragment

UPPER

Returns a string in all uppercase



Lava Database functions


AutoCommit

Specifies autocommit for the current Lava session

Clear

Deletes the nominated row of a given table

ColumnLabel

Returns the label of the nominated Lava table column

COMMIT

Commits any current open transaction frame

CREATETABLE

Creates a lava table and returns the table id

DROPTABLE

Drops a lava table

FindClose

Closes a seek identifier

FindColumn

Specifies a seek column for a seek identifier

FINDNEXT

Find the next match for a column search

FindRow

Find a row matching a given value for a nominated column

FindTable

Specifies the table for a seek identifier

FREEROW

Determine the first free row in a Lava table

LAVAERROR

Return the description for a nominated error code

LAVASTATUS

Return the status (success or error) for the last Lava or ODBC function call

OPENSESSION

Open a new Lava session

RenameTable

Renames the nominated Lava table

ReserveRows

Reserves a specified number of rows for the nominated Lava table

ROLLBACK

Perform a rollback on any open transaction frame

Session

Returns the current Lava session

SETSESSION

Set the current Lava session

SQL

Perform an SQL command on the Lava Server

TABLECOLUMNS

Return the number of columns in a nominated table

TableName

Returns the name of the nominated Lava table

TABLEROWS

Return the number of rows in a nominated table



ODBC Database functions


ODBC_ADD

Adds a row to an ODBC-linked database table

ODBC_CLOSE

Closes the nominated ODBC connection

ODBC_CONNECT

Connects to a nominated ODBC database

ODBC_SQL

Perform an SQL command on an ODBC database

ODBC_UPDATE

Performs an update to a nominated ODBC table row


String Functions


Char

Returns a character for a nominated ASCII value

IPfromString

Returns an IP identifier (numeric) from a given string IP

Lower

Converts a string to all lowercase

Ord

Returns an ordinal value for a given character

StringFromIP

Converts a numeric IP into a string

StringPos

Finds the position for a substring in a string

TrimAll

Trims spaces left and right of a given string

TrimLeft

Trims spaces from the left of a given string

TrimRight

Trims spaces from the right of a given string

Upper

Converts a string to all uppercase



Text output and formatting functions


FORMAT

Returns a formatted output for numbers in currency, percentage, date or time format

OUTPUT

Outputs text to the memory output buffer

TIME

Returns the current time in millisecond after midnight format

XMLFOOTER

Formats an XML segment footer

XMLHEADER

Formats an XML segment header

XMLROWDATA

Formats element data for a nominated rowtype



Text file functions


APPENDFILE

Opens an existing text file for writing, and returns the handle

CLOSEFILE

Closes an open file handle

CREATEFILE

Creates a new file or opens and truncates an existing file, and returns the file handle

READFILE

Reads text from an open file

SETFILEPOS

Sets the byte position in an open file

SETPATH

Sets the current default folder, and returns the previous default folder

SPACEFILE

Spaces column output in an open file to a nominated column

WRITEFILE

Writes text to an open file


Windows related functions


EXEC

Executes a command, executable or batch file

MESSAGE

Displays a message box

SLEEP

Executes a windows sleep for a given period

WINFILEEXISTS

Determines whether a nominated file / path exists

WINFILECOPY

 

WINFILEMOVE

 

WINFILEDELETE

 

WINFILERENAME

 

WINGETLASTERROR

 

WINFORMATMESSAGE

 

WINAPPENDMENU

 






Program Structuring Mechanisms


LavaStream is designed to allow large programs to be designed and written. In order to support this, a layered approach to software design is supported. From the lowest level up, this provides procedures, modules and projects to be defined to allow a hierarchy of code to be structured.


The project layer is supported only in Blueprint, whereas the module and procedure layers are supported directly in the LavaStream system.


Procedures


As with most high-level languages, LavaStream supports the definition of procedures with parameters in order to abstract certain functions or sets of instruction code. It is beyond the scope of this manual to define or explain the procedural mechanism in theoretical detail, and therefore the description below assumes a certain amount of programming knowledge and experience.


Procedures in LavaStream fall in two broad classes - private and public. Private procedures are visible only within a module, and cannot be invoked from external modules Public procedures may be called from external modules, and allow extension of the programming paradigm for a given module not only to modules within the module’s own project, but also to library procedures defined in foreign projects.


Procedure Declaration


A procedure is defined in terms of the declaration of a procedure framework, very similar to that in Pascal and identical to a definition in Oberon. An example follows.


PROCEDURE PureProcedure(parm1 : STRING; parm2 : INTEGER);

BEGIN

END PureProcedure;



The general procedure definition is provided by example below.


Functions


Functions are defined exactly as procedures, with a specified return type. An example follows.


PROCEDURE FunctionProcedure(parm1 : STRING; parm2 : INTEGER) : STRING;

BEGIN

     RETURN parm1[parm2..parm2+10];

END FunctionProcedure;


See also

Formal Procedure Declaration


Modules


A module directly corresponds to a single text file, with the extension .lava, referenced from the Blueprint environment through a LavaStream Module icon. A module may contain exported and / or private declarations of constants, types, variables and procedures. Through use of multiple modules in a project, a project may be divided into more manageable segments of code which may cross-refer to one another through the IMPORT mechanism. Refer to the section on the Import Mechanism below for further details.


A module may be used to encapsulate a number of procedures which logically belong together, such as for example a set of procedures relating to one particular data table, or a particular functional area such as vector calculations. In large projects, dividing the definition of procedures in this way makes it easier to maintain the source code and also allows different programmers to work on different source code modules simultaneously without conflicting.


Projects


LavaStream projects are made up of a set of LavaStream modules which should, at least nominally, be related to the functional responsibility of the project.


In the case of smaller projects, it may be that the project is entirely self-contained, and that the modules within the project fully define the functionality specified for the project.


For larger projects, the functionality may be divided between multiple projects, which use inter-project imports to access functionality defined in external projects in order to integrate the complete functionality required. See the section Import Mechanism below for further infromation.


A LavaStream project hierarchy is not limited in any way (except for mutual imports - see below) allowing extremely large software projects to be built through division into manageable projects each constructing part of the total functionality.


Due to the nature of the import mechanism, it is also possible to build libraries of functions which may be encapsulated within a project, for use by multiple other (perhaps unrelated) projects. There is no additional overhead at runtime when calling a function from an external project - such a function executes exactly as fast as a function in the local module.


Import Mechanism


LavaStream implements an explicit import mechanism (similar to some Pascal systems, and almost identical to those used in Modula-II or Oberon) to allow access of entities (constants, variables, procedures) across module boundaries.


Inter-module Imports


Unlike a language such as C, where external entities may be accessed freely provided some reference is present in (typically) an include file, in LavaStream only explicit references to external entities are provided. This means that all external references are prefixed by the name (or alias) of an explicitly imported module.


The following example illustrates in a simple way how the import mechanism works.


MODULE first;

 

CONST

 

(* Note in the following constant declaration the “-“ before the “=”, which specifies an exported constant *)

   PI - = 3.14159265359;

 

END first.


MODULE second;

 

IMPORT first;

 

CONST

(* Note the use of the imported constant PI below, through the nomination of the first module before the constant *)

   PIby2 = first.PI * 2;

 

END second;


In the above example you will see that the reference first.PI explicitly specifies the imported module as a prefix to the constant PI. It is not possible to refer to PI without this prefix - the main reason for this is the visibility provided by the mechanism. If a variable or procedure has no prefix, it is defined by the current module. If it has a prefix, it is defined in the module specified by the prefix. This makes source code more readable, and tracing the definition of an entity quite trivial.


Similarly to the above, cross-module references may be made to variables and procedures, allowing re-use of code and construction of very large projects with manageable division of source code.


Note that in any project where a module imports a second module, neither direct nor indirect mutual imports are supported. In other words, if module A imports module B, then module B may not import module A. Also, no module imported - directly or indirectly- by module B may import module A. Such mutual imports, direct or indirect, will result in a project which cannot be fully compiled.


Inter-project Imports


In addition to importing modules within a given project, imports may be specified across project boundaries. This allows reusable functionality to be defined within a project which serves multiple other projects with this functionality.


For example, a function may be defined in Project ProjA (within Module ModA) which is to be used on Project B. In Module BB (within project B) the import would be specified as follows :


IMPORT

     ProjA.ModA;


where the A. nominates the project from which the module is to be imported, and the AA nominates the module to be imported from that project. Any entity visible within the project (as exported from a given module) is also visible from other projects.


Similarly to imports for modules within a project, cross-project imports may not cause any loops in the import chain. In other words, under no circumstances may a module from project A import a module from project B if that module (directly or indirectly) imports the same module from project A.


Database Interfaces


LavaStream is primarily intended to provide application development for data-intensive requirements, typically those requiring at least one database. One of the aspects of the LavaStream environment which sets it apart from the majority of similar environments is the ability to interface - simultaneously and seamlessly - with multiple external ODBC databases as well as the integrated Lava database.


Lava Server Interface


This chapter has only a superficial treatment of the facilities presented by the Lava database. For a more detailed specification of the operation and functionality in the Lava Server and the Lava Database (including Lava SQL) please consult the Qubik Lava Server Reference.


The LavaStream environment is tightly integrated with the Lava database. Array-like access (both read and write) to Lava data tables allows simple and powerful access to data, while a comprehensive SQL interface also allows complex statements and joins to be processed where a row-level interface does not provide adequate functionality.


The interface with the Lava database is different from a conventional application / database interface, in that the LavaStream environment does not operate as a conventional client in a client / server connection. Instead, LavaStream operates on a distributed client database, which allows solutions to be coded as if on an exclusively mounted single-user database. The distributed link to the Lava Server takes care of the rest. In addition, even if the link to the main server is across a slow WAN link, it is possible to add a Lava Satellite Server to the site configuration, allowing the LavaStream client to interface at LAN speeds to the local server, while a background communication process ensures that the Primary Lava Server is kept up-to-date.


In addition to the above, LavaStream has the ability to create temporary (virtual) tables on the distributed client database serving the LavaStream environment. This allows very high speed storage and retrieval of (potentially) huge amounts of transient data which may be required for processing purposes.


SQL Interface


Where bulk operations are required, either to retrieve large result sets or to perform mass updates or deletions in the Lava database, a comprehensive SQL interface is provided which accepts any valid Lava SQL statement. A simple example is provided below.


   ResultTable := SQL(

     ‘select ‘ &

           ‘customer, code ‘ &

     ‘from ‘ &

           ‘accounts.invoice ‘ &

     ‘where ‘ &

           ‘delivery_date = 0');


In the above example, the SELECT statement will return a Lava Table ID into the table variable ResultTable, which may be manipulated as for any Lava table - including row-level access as described below.


There are many occasions when interfacing with a database where SQL is the most convenient way of achieving a particular result. However, it is very often true that the primary requirement is to operate on a particular row in a table. When this is the case, SQL can be quite clumsy - compare the methods described below for providing row-level access to the database.


Row-level Interface


In the majority of cases in a database application which presents a user interface to the database, access to the database is performed row by row. In these cases, performing the access via SQL is quite inconvenient. In order to present a more efficient interface, LavaStream allows direct integration with table data, as shown in the following simple example :


PROCEDURE FetchInvoice(pInvoice_id : INTEGER) : STRING;

VAR

   InvoiceRow : LAVA.Accounts.Invoice.TYPE;

   ReturnXML : STRING;

BEGIN

(*.Retrieve the nominated invoice *)

   InvoiceRow := LAVA.Accounts.Invoice[pInvoice_id];

   IF InvoiceRow.DeliveryDate = 0 THEN

      InvoiceRow.Status := ‘Undelivered’;

   ELSE

      InvoiceRow.Status := ‘Completed’;

   END;

(*.Update the database *)

   LAVA.Accounts.Invoice[pInvoice_id] := InvoiceRow;

(*.Generate XML *)

   ReturnXML := XMLHEADER(TRUE, 'items');

   ReturnXML := ReturnXML & XMLROWDATA('invoicedata', InvoiceRow);

   ReturnXML := ReturnXML & XMLFOOTER('items');

   RETURN ReturnXML;

END FetchInvoice;


Note that in the above example little or no knowledge of the complete invoice row structure is required - in contrast with the requirement for a SQL statement. Thus, it is possible to write code which is relatively independent of the exact table design, thereby creating more reliable programs.


Row-Level Seek


It is often necessary to locate a related row from given data, where nested processing in detail tables is to be performed (or for any other reason). In order to allow the location of row data directly without recourse to SQL, LavaStream presents a facility for finding rows in a data table directly, returning the row ID of the matching row(s).


Consider the following example :


PROCEDURE FindInv();

VAR

   Seek_id : INTEGER;

   InvDtl : LAVA.Account.InvoiceDetail.TYPE;

   Header : LAVA.Account.InvoiceHeader.TYPE;

   Header_id : INTEGER;

   Row_id : INTEGER;

BEGIN

   FOR Header_id := 1 TO 100 DO

      Header := LAVA.Account.InvoiceHeader[Header_id];

      OUTPUT('Header : ' & Header.ID & ' ' & Header.Order_no & NEWLINE);

      Row_id := FINDROW( Seek_id,

                          LAVA.Account.InvoiceDetail,

                          LAVA.Account.InvoiceDetail.Order_no,

                          Header.Order_no);

      WHILE Row_id # 0 DO

         InvDtl := LAVA.Account.InvoiceDetail[Row_id];

         OUTPUT(' ' & InvDtl.ID & ' ' & InvDtl.Order_no & ' ' & InvDtl.Stock_code & NEWLINE);

         Row_id := FINDNEXT(Seek_id);

      END;

      FINDCLOSE(Seek_id);

   END;

END FindInv;


Note that the above example is not supposed to be very clever - the result would have been easier to reach through SQL. However, the functionality presented by the FIND / NEXT functions is clearly presented.


The above example illustrates a simple single-column seek. More complicated seeks based on multi-column conditions may also be executed - see the FINDCOLUMN command for an example of a multi-column seek and information on specifying inequalities as seek conditions.


Lava Interface Selection


From the above information, it is clear that under some circumstances the conventional SQL technique will be more efficient. On these occasions, it is often best to simply use SQL. However, there are many occasions where SQL would be an inconvenient way to program a particular data access or update. In these cases, the row-level access, update and seek mechanisms may be used as an alternative to SQL in order to optimize the processing and achieve the result in a more direct manner.


Note that depending on the number of rows to be accessed, each of these techniques has advantages. Where a few rows (say 100 or less) are to be processed, it is highly likely that a row-level approach will be more efficient and will result in faster processing. For large numbers of rows to be retrieved or updated (almost certainly where thousands of rows are involved) SQL is likely to execute faster.


It is also possible to use both of these techniques together, provided that the row ID is selected when selecting the result set. In such a case, the row ID may be used to perform row-level operations or further exploration of related data, while the SQL data is used for the primary operations.


Error checking


Directly after any Lava database function has been executed, the success or failure of the function may be checked using the LAVASTATUS function. The following code segment illustrates this technique :


   rc := LAVASTATUS();

   IF rc # 0 THEN

(*.Perform any error processing here *)

   END;


The variable rc in the above example (an abbreviation for return code) will be 0 if the previous operation has succeeded, and non-zero if it failed for whatever reason. A textual explanation of the failure code may be obtained as follows :


   ErrorText := LAVAERROR(rc);



ODBC Interface


In order to allow for import from and export to foreign databases, LavaStream includes a comprehensive, high-speed ODBC interface.


In addition to the ability to execute SQL statements across the ODBC connection, LavaStream also has built-in facilities to allow simple insertion and update of rows in ODBC data tables.


To support large-scale import of data from an ODBC source, LavaStream provides for the creation of Lava data tables directly through the execution of an SQL statement through an ODBC connection. This allows rapid and flexible import of data from (potentially) multiple ODBC sources in order to construct consolidated databases from (potentially) multiple sites.


Connecting to ODBC database servers


It is possible to connect to an ODBC server in one of two ways. In both cases, a Connect statement is issued; in one a so-called DSN (Data Source Name) is used, and in the other the driver’s specific connect fields are entered directly. Compare the following examples :


   Connection := ODBC_CONNECT(‘DSN=SQL_dsn’);


Here, an existing DSN is used. Such a DSN must be created using the Data Sources (ODBC) dialog provided by Windows - this can normally be found in the Administrative Tools section of the Windows Control Panel.


   Connection := ODBC_CONNECT(‘DRIVER=SQL Server;’ &

                             ‘SERVER=WindowsSQLserver;’ &

                             ‘UID=ValidUsername;PWD=CorrectPassword;' &

                              ‘WSID=FredsWorkstation;Network=DBMSSOCN');


In this case, the parameters for a Microsoft SQL Server are completed explicitly - this can normally be done for any ODBC Server, but the user must know the parameter names and required values in order to be able to construct the connect string correctly.


SQL Interface


In almost all cases, the only interface an ODBC connection has to the ODBC Server is through SQL. LavaStream presents a number of pseudo-interfaces (as listed below) but these in fact all use SQL to interface to the ODBC database. Where these pseudo-interfaces do not provide the functionality required, a general-purpose SQL interface may be used, as shown in the following example :

   Resulttable := ODBC_SQL(Connection,

      "select " &

         “invdtl.order_no, invdtl.order_line_no, invdtl.warehouse, “ & “invdtl.product, invdtl.weight “ &

      "from " &

         "FAT.scheme.opdetm as invdtl");


The above example assumes that a valid ODBC connection has been obtained, and should use the correct SQL syntax for the target database.


A statement such as the one above will result in a Lava data table (the table ID for which is returned in the variable Resulttable). This result table may be processed as for any Lava table, with the single difference that the programmer must define the row type himself. For the above example, such a row type definition may look as follows :


   InvoiceDetailType = ROWTYPE

      Order_no : STRING[50];

      Line_no : INTEGER;

      Warehouse : STRING[70];

      Product : STRING[100];

      Weight : FLOAT;

   END;


It will also be necessary to declare a variable of the above row type, perhaps as follows :


VAR

   InvoiceDetailRow : InvoiceDetailType;


Result Row Access


Having defined the row type as shown above, it is possible to retrieve individual result rows from the result table as follows :


   FOR Index := 1 TO TABLEROWS(Resulttable) DO

      InvoiceDetailRow := Resulttable[Index];

(*....Perform required processing here *)

   END;


Note that although nothing prohibits you from updating the result table (it is a table like any other) no such update will be reflected on the ODBC server - there is no link between the result table and its origin.


Row Insertion


In order to provide a more reliable and less time-consuming method for inserting data into an ODBC data table, LavaStream presents the ODBC_ADD function. This allows interaction with an ODBC data table based on the name of fields in a row type definition, with the LavaStream engine doing the majority of the work in terms of constructing the bulk of the SQL insert statement required.


Using the row type definition as above, a row may be added to the ODBC server as follows :


   ODBC_Add(Connection, ‘FAT.Scheme.opdetm’, InvoiceDetailRow);


The implicit assumption is that the row type variable, InvoiceDetailRow, contains the values required to be added to the ODBC data table. Given that this is the case, the above instruction could generate SQL approximately as follows :


insert into FAT.scheme.opdetm

              (order_no, line_no, warehouse, product, weight)

values

              (‘01', 2, ‘aa’, ‘prod1', 23.5)


Row Updates


Similarly to the method above for inserting new rows, LavaStream also supports the update of existing rows in an ODBC table. In this case, the programmer has to specify an appropriate filter clause which will select the row to be updated.


Note that the filter specified must be adequate to select only the row to be updated - if the filter is incorrect or not selective enough, all rows selected will be updated. The onus is on the programmer to ensure that the filter will correctly select the appropriate row.


The example below illustrates the use of a row update, given the row types and variables as defined above :



   ODBC_UPDATE( Connection,

                ‘FAT.Scheme.invoice_lines’,

                InvoiceDetailRow,

                ‘order_no = “01" and line_no = 2');



Closing ODBC connections


Depending on the operations performed while connected to an ODBC source, a significant number of resources may be allocated to such a connection. In all cases it is a good idea to disconnect from the server when the connection is not in use - this allows LavaStream to free all allocated resources and also allows the ODBC Server to free any resources allocated to the connection. The following example illustrates how this is done.


   ODBC_CLOSE(Connection);


If the connection is already closed, the function has no effect.


Text File and Structure Interfaces


Text File Interface


LavaStream provides a comprehensive text file interface, allowing the programmer to create or append to text files. In addition to the facilities provided for writing values, text files may also be read, while comprehensive string processing facilities allow formatting or decoding of string values.


Writing Text Files

In order to write to a text file, the file can either be created (using the CREATEFILE function) or appended (using the APPENDFILE function). In both cases, if the file has been successfully opened, any string value may be written to the file using the WRITEFILE function.


If CREATEFILE is used to open an existing file, the file will be truncated (cleared) on open. If the content of the file should be preserved, use APPENDFILE instead. If an existing file is opened using APPENDFILE, the default file position will be at the end of the file, allowing text to be appended to the end of the file without further adjustment being necessary.


WRITEFILE allows any text to be output to the file - consistent with all other string processing in LavaStream, this means that any of the functions resulting in string output may be used, in conjunction with the automatic casting of values to text if appended / concatenated using the & operator.


Facilities such as FORMAT, STRINGFROMIP and UPPER / LOWER may be used in the parameter for WRITEFILE to create or format output for the text file.


In order to allow text files to be formatted in a columnar style, the SPACEFILE function allows the line output to be aligned on a nominated column to the right of current output.


Reading Text Files

To read from a text file, the file should be opened using the APPENDFILE function - this will open an existing file without clearing the content.


In order to provide for reading input, the file pointer should first be set using the SETFILEPOS function - the default file pointer position for a file opened with APPENDFILE is at the end of the file.


Once the file has been opened and the file pointer set, successive READFILE functions may be called to read text data from the file. The READFILE function allows any desired termination string fragment to be specified, consisting of 1 or more characters on which the read operation is to terminate. This allows highly flexible input from text files.


It is possible and permissible to write text to a file which is being read - the onus is on the programmer to ensure that the data written will be correctly placed in the file. The file pointer is moved on as reads are performed, and always points to the next character to be read. If a WRITEFILE is performed at this point, it will overwrite the number of characters provided in the string specified, and will move on the file pointer by the same number of characters.


Completing File I/O

Once all input or output has been concluded, the file should be closed using the CLOSEFILE function. This will ensure that all data buffered by the operating system has been written to the file, and will free the file for use by other programs.


XML Interface


LavaStream provides a highly functional set of XML interface functions, providing for both input from and output to XML formatted data.


XML is rapidly becoming a very important data format - aside from long-standing use in the Internet environment as a method for communicating structured data, XML is now also the default format for Microsoft Excel.


XML Import


In order to import XML data, it is necessary to have a structure correctly formatted and named to accept the data contained in the XML string.


For example, given the following XML data :


<?xml version="1.0" encoding="utf-8" ?>

<items>

   <formdata>

      <session>327</session>

      <name> John</name>

      <title>mr</title>

   </formdata>

</items>


It will be necessary to define a ROWTYPE structure corresponding to the XML data, similar to the example below :


   FormRowType = ROWTYPE;

      Session : STRING[100];

      Name : STRING[100];

      Title : STRING[20];

   END;


Finally, a variable of the above type will be required, perhaps as follows :


VAR

   FormRow : FormRowType;


Given the data and code segments as above, the following instruction will extract the XML data into the row type variable, assuming that the variable XMLstring contains the XML segment specified :


   FormRow := XMLstring;


The LavaStream Runtime will automatically detect the XML content in the string variable nominated, and will parse the XML data into the row type variable.


Note that the exact sequence of the above row type does not have to correspond exactly to the XML data; the XML import functionality will match the individual data items based on naming rather than on position. Also, the match is not case sensitive, and will match the first field name which is equivalent regardless of case. It is important to note, therefore, that although LavaStream will permit distinct fields in a row type to be defined identically except for specific character case, an XML import with equivalent fields will successively match to the first field, leaving the second (case non-identical) field blank.


XML Export


In order to output XML formatted text, a suitably defined ROWTYPE definition and variable are required - similarly to the requirement for XML import described above.


Given the same row type definition and variable declaration as in the above section, the following code segment could be used to output XML text :


   Session := 327;

   Name := “John”;

   Title := “mr”;

 

(*.Outer tag *)

   OUTPUT(XMLHEADER(TRUE, 'items'));

(* Form group *)

   OUTPUT(XMLROWDATA('formdata', FormRow));

(*.End outer tag *)

   OUTPUT(XMLFOOTER('items'));


This code sequence will output an XML text segment identical to the XML segment specified above as the input for the XML import.


Note that conventionally the data for the row type variable would probably have been read from a data table, perhaps as follows :


   FormRow := LAVA.SessionSchema.Session[Session_id];


where the table definition for the nominated table matches the field / column definitions in the row type.


Programming Environment



The primary environment for developing LavaStream projects and source code is Qubik Blueprint. Blueprint is a graphical project environment, allowing extensive definition of both LavaStream projects as well as data dictionaries for use in LavaStream projects and Web-based form definition for auto-generated application development.


This chapter is a brief introduction to the Qubik Blueprint environment. For a more detailed coverage of the methods and techniques used when programming using Qubik Blueprint and LavaStream, see the Qubik Blueprint Operations Guide.


Blueprint Operating Principles


Unlike the majority of other software development environments, Blueprint is based entirely on a central database. All projects, attributes and even source code are stored centrally in a Lava database, and all developers working in Blueprint access the same data from the same database. Although it is possible to configure Blueprint to place a copy of the source code on your workstation, the reference copy of the source is kept in the database and is accessed and updated by all developers logged in to the database. All programmers see the latest version of the source code, and operate on the latest project definitions and data dictionaries.


As LavaStream is an interpreted language which runs from a database image, compiled source (a LavaStream module image) is also stored in the central database.


There are, then, no files stored on your workstation unless you specifically configure Blueprint to place copies in a nominated folder. Everything comes from the central Lava Server.


Programming using Qubik Blueprint


The Blueprint Development Environment allows creation and management of both LavaStream Projects and Lava Data Dictionaries, ranging from small to extremely large.


Graphical Object Management


The Blueprint Development Environment is a graphical environment, which allows definition and management of projects and modules through a graphical depiction of these objects through the use of nodes on a programming desktop.


The environment as viewed at any one level allows definition (creation), viewing and setting of attributes for a number of objects or nodes which may include LavaStream Projects, Dictionaries, or - below project level - LavaStream Modules.


An example of a desktop layout including several defined objects is depicted below.



qubiklavastreamlanguagereference4.gifB lueprint Desktop

 


The above example depicts two LavaStream Projects (Accounting and Back-Office) and a single dictionary (Accounting).


The desktop depicts a layer in the design, and it is possible to descend through a node to the layer below. In the above example, double-clicking on a node or clicking on the node hotspot (a small rectangle to the bottom right of the node, just above the node label) descends to the layer below. In the case of a LavaStream project, this layer will probably contain one or more LavaStream modules, or perhaps further projects in the case of a larger project hierarchy. In the case of a dictionary, the lower layer will probably contain several table nodes, and perhaps also one or more subordinate dictionary nodes.


The total desktop is much larger than the viewing area, and may be viewed by using the desktop map presented to the left of the desktop. The small red square in the map represents the viewing area. The viewing area may be moved by clicking and dragging the red square in the map and sliding it to any desired area on the total desktop. The viewing area will follow the map to the desired region.


Creating Nodes


In order to create a new node on the current Blueprint desktop, simply click on the node selection button as depicted below :


qubiklavastreamlanguagereference5.gifNode Selection Button





 


A drop list will appear listing the available node types. Select the appropriate node type, and click on the desktop to create the node.


Once the node is created, it should be re-named to something appropriate. To do this, select the node by clicking on it (the node will highlight) then press F2 to edit the label. Press Enter when done.


LavaStream Projects

 

In order to group related functionality and to allow management of large-scale software development, LavaStream modules are grouped into projects. Through this mechanism, combined with the ability to define hierarchies of projects (projects containing lower-level projects, perhaps through multiple levels) it is possible to divide very large projects into more manageable sub-projects which may be used as parts or libraries to construct the full set of required functionality.


LavaStream has the ability to import functionality both from other modules within a project, as well as from modules belonging to other projects. The combination of the provision for projects at multiple levels and the ability to import functionaty from subordinate projects means that software projects of almost arbitrary complexity may be constructed.


LavaStream Modules


A LavaStream module is represented by a module node on the Blueprint desktop, and contains software source code in the form of LavaStream programming. This source code is stored in the main Lava database, and is available to all Blueprint users regardless of which workstation they are operating on.


Editing and Compiling LavaStream Modules


In order to edit a LavaStream module, right-click on the LavaStream module node and select Edit Source from the pop-up menu. This will invoke the Blueprint Editor, which allows modification and compilation of source code.


Editing in the Blueprint Editor is very similar to other multi-source editors.

There are a few facilities which provide convenient functionality worth knowing about.


qubiklavastreamlanguagereference6.gifBlueprint Editor


 


In the partial image of the Blueprint Editor above, the following facilities are important :


Module List

The list in the top left corner of the image is the module list. These are the source modules currently loaded in the editor, and any particular module may be selected by clicking on it with the mouse. It is also possible to select a module by first switching to the module list by pressing Ctrl-F (for File), then selecting the desired module either using the up or down arrow keys or by pressing the first letter of the name of the module, then pressing Enter when the desired module is highlighted.


Procedure List

The list on the lower left of the image is the procedure list for the current module. These are all procedures defined in the source module, and you may navigate to any one of these procedures by clicking on the procedure name with the mouse. It is also possible to select a module by first switching to the module list by pressing Ctrl-P (for Procedure), then selecting the desired procedure either using the up or down arrow keys or by pressing the first letter of the name of the procedure, then pressing Enter when the desired procedure is highlighted.


Compile Button

Above the source code and just to the right of the module list is the compile button (the leftmost of the two buttons presented). The current module may be compiled by clicking on this button.



Dictionary Definition


The Blueprint Dictionary system allows definition of named dictionaries, which serve as an encapsulating mechanism for defining one through many data tables which are part of the dictionary.


In addition, the dictionary system allows hierarchies of dictionaries. If the intended dictionary will be too large to be defined in a single dictionary page, Blueprint allows subordinate dictionaries to be defined within a dictionary, and will generate all data tables at all levels within a dictionary hierarchy as if they belong to the topmost dictionary in the hierarchy.


In addition to allowing for very large dictionaries, this mechanism allows dictionaries to span any number of schemas in the database. Each dictionary nominates the schema into which the tables defined will be placed, but subordinate dictionaries do not have to nominate the same schema, and may place their tables in any required schema.


Within any dictionary in a hierarchy of dictionaries, an alias (synonym) table may be defined for any other table in any other dictionary, to allow for relations to be defined between tables in different dictionaries. See Definition of Relations for further details.


Table Definition


Within any dictionary, data tables may be defined. A table may be defined from the ground up, by creating a dictionary table icon through the toolbar, after which attributes and columns for the table may be defined through the table property interface.


Alternatively, if the table currently exists in the Lava Database (perhaps due to restoring a backup, or due to creation of the table through SQL commands) such a table may be imported into the dictionary by using the table import mechanism accessed by right-clicking on the Blueprint desktop and selecting the Import option.


A table may be created on the desktop by clicking on the node creation button to the top left of the Blueprint desktop, then selecting Dictionary Table from the list. Note that tables may only be created below a dictionary node - dictionaries are the encapsulating entity for tables, and allow the generation of SQL for the creation of the tables contained in the dictionary.


The following image depicts a small dictionary as defined in Blueprint.

qubiklavastreamlanguagereference7.gifDictionary Example




 



In the above example, three tables are depicted in a dictionary called “System Dictionary”, and two relations (the lines between the tables) are shown. There is also a fourth table in the off-viewing area, as can be seen in the map.


Column Definition


Columns may be defined or amended for any dictionary table by right-clicking on the table node and selecting Table Properties from the pop-up menu.


The Table Properties window allows comprehensive definition of the table. An example is presented below, using the Sys_Parameter table from the above dictionary image.


qubiklavastreamlanguagereference8.gifDictionary Table Properties

 


In the above image, the attributes for the table may be seen toward the bottom of the image (Table Type, Distribute, Update, Alias) - these properties are described in detail in the Qubik Blueprint Operation Guide.


The columns for the table may be seen directly above the attributes. The column label, sequence number and type may be seen - there are a number of other column attributes toward the right of the window (not shown).


At the mouse position are three buttons; from left to right : Delete column, Move down, Move up.


A little higher up,, to the left of the Column tree label, is the Column Create button. This allows addition of new columns into the column list.


Definition of Relations


To define a new relation between two tables, first select the Relation tool from the tool list, shown under the mouse in the following example :


qubiklavastreamlanguagereference9.gifBlueprint Relation Tool








 


Once the relation tool has been selected (the mouse cursor will change) a relation may be defined by clicking on the first table node, then dragging to the second table node and releasing the mouse over it. A relation line will be drawn between the two nodes.


The relation may be fully defined by right-clicking on the relation line and selecting Relation Properties from the pop-up menu.


qubiklavastreamlanguagereference10.gifTable Relation Properties

 


Using the Relation Property window, the type of relation and the columns representing the relation may be defined. Advanced relation properties are discussed in the Qubik Blueprint Operation Guide.


Generating a Dictionary



Creating Data Tables on a Lava Server


Integrating LavaStream with a Dictionary Schema




Testing using LavaStream Elements


The LavaStream Elements test environment allows execution of LavaStream procedures directly without recourse to the Lava Scheduler or invocation through Apache Web Server. This environment is used primarily for two purposes :

 

            Evaluating LavaStream procedures in a standalone test environment

            Executing batch procedures written in LavaStream which perform data imports or data modification


In the first case, a LavaStream procedure may be executed in order to examine the results of the execution either in text form in the output editor, or to check data output using the database object viewer.


In the second case, LavaStream Elements is merely used as a means of invoking a procedure, optionally with parameters, in order to execute the procedure in a similar way to clicking on an icon on the Windows desktop or invoking a program from the start menu.


In an alternative to the above invocation, it is possible to configure an icon in the Blueprint Desktop which will invoke the procedure optionally with nominated parameters.


Adjusting the Elements Mount Parameters


LavaStream Elements may be mounted in one of two ways. The first (and default) is client mode. This yields the same form of connection presented within the Blueprint Editor for executing LavaStream procedures. The second is exclusive mount. This allows fast execution of procedure without the overhead of distributed data transmission between the client and the Lava Server.


Running in Exclusive Mount


To use LavaStream Elements in exclusive mount, the parameters to the Elements executable need to be modified. You may want to create a second copy of the shortcut in order to retain the default (client) mount parameters.


The default parameters may be found by first expanding the Start Menu to the LavaStream Elements entry below the Qubik menu, then right-clicking on the entry and selecting the “Properties” option. The parameters are presented in the “Target” entry field of the Properties dialog.


If you wish to make a copy of the Start Menu entry for the Elements application, you may click-and-drag the Start Menu entry to the desktop, then hold Shift+Control while dropping the entry on the desktop. This will form a new shortcut to the application.


Once you have made a copy of the shortcut, the parameters may be modified from the default by right-clicking on the shortcut and selecting the “Properties” option. Modify the “Target” entre from the default, something like this :


/ClientPath=S:\Temp\lava /User=Fred /Password=BloggsPass /server=LavaServer


After modifying the above parameters to exclusive mount mode, the parameters could look as follows :


/User=Fred /Password=BloggsPass /Datapath=D:\Qubik\LavaPrimary


(Assuming that the main database is located at the path D:\Qubik\LavaPrimary).


Should it be appropriate, you may also wish to change the login parameters to the system account (the default would be user system, password manager - the password may have been changed by your database administrator).


Executing a LavaStream Procedure


Once you have connected to the database with LavaStream Elements (either in client mode or in exclusive mode, depending on requirements) the procedure to be executed may either be typed into the command section of the main interface (the upper edit box in the window depicted below) :

qubiklavastreamlanguagereference11.gif

In the above example, the procedure ImportProc which accepts two parameters, a string and an integer, is invoked as follows :


qubiklavastreamlanguagereference12.gif

Note that the specification of the procedure to be invoked is case sensitive, and must therefore match the definition of the project, the module and the procedure exactly.


Provided that the command is entered correctly, the procedure will be executed and any output produced by the procedure will be displayed in the lower edit box.



Selecting a LavaStream Procedure for execution


Instead of typing in the command to execute the procedure, it is possible to select the procedure from a procedure tree. The tree interface may be invoked by selecting Admin / Parse Tree from the LavaStream Elements menu. Once the parse tree has been expanded to the required module, a procedure may be invoked, as follows :

qubiklavastreamlanguagereference13.gif

The Execute Procedure option may be selected by right-clicking on the entry for the required procedure.


Should any parameters be required by the procedure, these may be typed into the entry field at the top of the window.


Viewing Output


After completion of execution, any output generated using the OUTPUT command in LavaStream will be reflected in the lower of the two edit boxes in the main LavaStream Elements interface window. The edit box is not limited in any practical way, and will permit large output buffers to be displayed in a scrollable window.


Debugging LavaStream


The LavaStream debugger is integrated into the Blueprint Editor. To invoke the debugger on a procedure, first edit the module in which the procedure is defined. Be sure to compile the module before invoking the debugger, and check that the module compiles without errors.


To invoke the debugger, right-click on the procedure in the procedure list, and select the debug lavastream option


qubiklavastreamlanguagereference14.gifInvoking the Debugger







 


Provided the procedure is consistently compiled and without errors, the debugger will start at the first instruction of the selected procedure. A typical depiction of the debugger interface is shown below :


qubiklavastreamlanguagereference15.gifLavaStream Debugger

 


Once the debugger has been invoked, the following facilities are available :


Examine Variables

The Debug Variables window will display all variables - parameters, local variables, array variables and module variables - which are in scope. These are divided into three sections :


Variables

Displays all simple variables in scope.


Arrays

Lists array variables. The currently defined elements of the array are shown - as array size is dynamic, this will be the size of the array as defined by the highest index of the array used to this point in the code.


Structures

Lists structure variables - both row type variables and Lava table variables. The full content of the structure is displayed.



Setting Breakpoints

Breakpoints may be set at any point in the executable source code. To set a breakpoint, either click in the gutter at the line where the breakpoint is required, or move the cursor in the source window to the line on which the breakpoint is to be set and press F9.


Once a breakpoint has been set, parameters applying to the breakpoint may be adjusted in the breakpoint tab below the source code window. An example is shown below :




qubiklavastreamlanguagereference16.gifDebugger B reakpoints

 


From the example it can be seen that breakpoints may be :


Unconditional

An unconditional breakpoint triggers whenever the execution pointer reaches the nominated source line


Disabled

A disabled breakpoint does not trigger, and is functionally equivalent to not having a breakpoint. If the breakpoint is re-enabled, it is once again active.


Conditional

Breakpoints may be set as conditional on the basis of the number of times the breakpoint is triggered. The breakpoint only triggers when the condition becomes true.


Executing the Code

Code execution may be achieved either through the toolbar buttons at the top of the debugger source window, or through the function key shortcuts as listed below.


Note that variable display is only refreshed when the debugger is halted.


Step Over - F10

This will step to the next source line in sequence, stepping over any procedure calls encountered.


Step Into - F11

If the current source line is a procedure call, the debugger will step into the called procedure.


Step Out

The debugger will run to the end of the current procedure, and break on the first line of code following the call to the procedure.


Go to Breakpoint - F5

The code is executed until the first valid breakpoint is encountered.


The specific function keys were selected as these function keys (with some variation) have become a de facto standard in debuggers. The most common assignments were selected.


Viewing Output


While debugging code, and at every break in debug execution, the debugger updates the output window as depicted below.


Output is generated through the LavaStream OUTPUT command, as in the following example :


   OUTPUT(‘Matrix element ‘ & Index & ‘ : ’ & Matrix[Index]);


Using this technique additional information on execution may be obtained than is visible from the variable window. The Output command as above is also used to generate output when in the Apache environment; i.e. all HTML and XML output to the browser client is generated in this way.

qubiklavastreamlanguagereference17.gifDebugging Output

 



Exit the Debugger

The debugger may be exited either by clicking on the button in the toolbar or by pressing Ctrl-B. This will terminate the debug session and restore the editor to its usual state. The debugger may be re-invoked, or other editing functions may be performed.


LavaStream Syntax


Formal Syntax


The following formal syntax definition is very similar to that for the programming language Oberon, and also has large similarities with Pascal and Modula. In general, the language is somewhat simplified as compared with Oberon, but obeys the same design principles.

 

ident                  =    letter {letter | digit}.

number                 =    integer | real.

integer                =    digit {digit} | digit {hexDigit} "H" .

real                   =    digit {digit} "." {digit} [ScaleFactor].

ScaleFactor            =    ("E" | "D") ["+" | "-"] digit {digit}.

hexDigit               =    digit | "A" | "B" | "C" | "D" | "E" | "F".

digit                  =    "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9".

CharConstant           =    ‘"’ character ‘"’ | digit {hexDigit} "X".

string                 =    ‘"’ {character} ‘"’ .

qualident              =    [ident "."] ident.

identdef               =    ident ["*"].

TypeDeclaration        =    identdef "=" RowType.

RowType                =    ROWTYPE FieldListSequence END.

FieldListSequence      =    FieldList {";" FieldList}.

FieldList              =    [IdentList ":" type].

IdentList              =    identdef {"," identdef}.

VariableDeclaration    =    IdentList ":" type.

designator             =    qualident {"." ident | "[" ExpList "]" | "(" qualident ")" | "^" }.

ExpList                =    expression {"," expression}.

expression             =    SimpleExpression [relation SimpleExpression].

relation               =    "=" | "#" | "<" | "<=" | ">" | ">="

SimpleExpression       =    ["+"|"-"] term {AddOperator term}.

AddOperator            =    "+" | "-" | OR .

term                   =    factor {MulOperator factor}.

MulOperator            =    "*" | "/" | DIV | MOD | "&" .

factor                 =    number | CharConstant | string | NIL | set | designator [ActualParameters] | "(" expression ")" | "~" factor.

ActualParameters       =    "(" [ExpList] ")" .

statement              =    [assignment | ProcedureCall | IfStatement | CaseStatement | WhileStatement | RepeatStatement | LoopStatement | [expression] ].

assignment             =    designator ":=" expression.

ProcedureCall          =    designator [ActualParameters].

IfStatement            =    IF expression THEN StatementSequence

                             {ELSIF expression THEN StatementSequence}

                             [ELSE StatementSequence]

                             END.

CaseStatement          =    CASE expression OF

                             {"|"} case {"|" case}

                             [ELSE StatementSequence]

                             END.

Case                   =    [CaseLabelList ":" StatementSequence].

CaseLabelList          =    CaseLabels {"," CaseLabels}.

CaseLabels             =    ConstExpression [".." ConstExpression].

WhileStatement         =    WHILE expression DO

                             StatementSequence | LoopControl

                             END.

LoopStatement          =    LOOP

                             StatementSequence | LoopControl

                             END.

RepeatStatement        =    REPEAT

                             StatementSequence | LoopControl

                             UNTIL expression “;”

ForStatement           =    FOR ident “:=” Expression TO Expression [BY ConstExpression] DO

                             StatementSequence | LoopControl

                             END.

LoopControl            =    CYCLE | EXIT

ProcedureDeclaration   =    ProcedureHeading ";"

                             ProcedureBody ident.

ProcedureHeading       =    PROCEDURE identdef [FormalParameters].

ProcedureBody          =    VAR {VariableDeclaration ";"}}

                             [BEGIN StatementSequence]

                             END.

ForwardDeclaration     =    PROCEDURE "^" identdef [FormalParameters].

FormalParameters       =    "(" [FPSection {";" FPSection}] ")"

                             [":" qualident].

FPSection              =    [VAR] ident {"," ident} ":" FormalType.

FormalType             =    qualident.             

DeclarationSequence    =    {CONST {ConstantDeclaration ";"} |

                             TYPE {TypeDeclaration ";"} |

                              VAR {VariableDeclaration ";"}}

                             {ProcedureDeclaration ";" |

                             ForwardDeclaration ";"}.

Module                 =    MODULE ident ";"

                             [ImportList]

                             DeclarationSequence

                             [BEGIN StatementSequence]

                             END ident "." .

ImportList             =    IMPORT import {"," import} ";" .

Import                 =    ident [":=" ident].




LavaStream Functions


A wide range of functions are natively supported in LavaStream. These are broadly divided into 6 categories of functions as described below.



Date and Time functions


Date

The DATE function returns the current date in Julian format


DateVar := DATE();


Parameters

None.


Return values

The current Julian date, a numeric value.


Remarks

As the returned date is in numeric format, representing the number of days since the year 300 CE, date arithmetic may be performed by simple subtraction or addiction.


The return value may be converted to a text representation using the Format function.


The return variable may be specified either as an INTEGER or as a DATE. If specified as a DATETIME, only the date portion (the integer portion) will be set - the time portion (the fractional portion) will be left blank, i.e. midnight..


DateFormat

The DATEFORMAT function sets the default date format for conversion purposes.


DATEFORMAT(FormatX.FORMAT_S_DATE_4);

DateVar := StringVar;


Parameters

Date format constant


Return values

None.


Remarks

After setting the default date format, when assigning string variables into a DATE - type variable, the string is interpreted to be formatted in the specified way. Provided the string has this format, it will be converted into a Julian date corresponding to the string date.


See also

Specific Typecasting (Dates)


Day

The DAY function returns the day of the month from a date or datetime variable containing a valid date


DATE(DateVar);


Parameters

              DateVar               :             A DATE or DATETIME variable containing a valid julian date, typically returned by the DATE or DATETIME functions.


Return values

The day of the month represented by the nominated date parameter.


Remarks

The return value is numeric, and if used in string construction will yield a single digit if the day is less than 10. If more formal string date construction is required, see the FORMAT function.



Hour

The HOUR function returns the hour of the day in 24 hour format from a time or datetime variable containing a valid time.


HOUR(TimeVar);


Parameters

              TimeVar              :             A TIME or DATETIME variable containing a valid Lava time, typically returned by the TIME or DATETIME functions.


Return values

The hour of the day in 24 hour format represented by the nominated time parameter.


Remarks

The return value is numeric, and will range from 0 through 23.


Minute

The MINUTE function returns the minute of the hour from a time or datetime variable containing a valid time.


MINUTE(TimeVar);


Parameters

              TimeVar              :             A TIME or DATETIME variable containing a valid Lava time, typically returned by the TIME or DATETIME functions.


Return values

The minute of the hour represented by the nominated time parameter.


Remarks

The return value is numeric, and will range from 0 through 59.


Month

The MONTH function returns the month of the year from a date or datetime variable containing a valid date


MONTH(DateVar);


Parameters

              DateVar               :             A DATE or DATETIME variable containing a valid julian date, typically returned by the DATE or DATETIME functions.


Return values

The month of the year represented by the nominated date parameter.


Remarks

The return value is numeric, and if used in string construction will yield a single digit if the month is less than 10. If more formal string date construction is required, see the FORMAT function.


Second

The SECOND function returns the second of the minute from a time or datetime variable containing a valid time.


SECOND(TimeVar);


Parameters

              TimeVar              :             A TIME or DATETIME variable containing a valid Lava time, typically returned by the TIME or DATETIME functions.


Return values

The second of the minute represented by the nominated time parameter.


Remarks

The return value is numeric, and will range from 0 through 59.


TimeFormat

The TIMEFORMAT function sets the default time format for conversion purposes.


TIMEFORMAT(FormatX.FORMAT_S_TIME_4);

TimeVar := StringVar;


Parameters

Time format constant


Return values

None.


Remarks

After setting the default time format, when assigning string variables into a TIME - type variable, the string is interpreted to be formatted in the specified way. Provided the string has this format, it will be converted into a Lava time corresponding to the string time.


See also

Specific Typecasting (Times)


Year

The YEAR function returns the current year from a date or datetime variable containing a valid date


MONTH(DateVar);


Parameters

              DateVar               :             A DATE or DATETIME variable containing a valid julian date, typically returned by the DATE or DATETIME functions.


Return values

The year represented by the nominated date parameter.


Remarks

The year is returned in complete form, in other words if the date variable contains the Julian date for (say) 1 January 2007, the YEAR function will return the numeric value 2007.


Time

The TIME function returns the current time in fractional format.


TimeVar := TIME();


Parameters

None.


Return values

The current time, represented as a fraction of a day.


Remarks

As the time is represented in a simple numeric format representing a fraction of a day, arithmetic may be performed where time calculation is required.


The return value may be converted to a text representation using the Format function.


Datetime

The DATETIME function returns the current date and time in a integer (date) and fraction (time) format.


DateTimeVar := DATETIME();


Parameters

None.


Return values

A DateTime variable, represented in floating point. The integer portion is the Julian date, and the fractional portion is the number of milliseconds since midnight, divided by the number of milliseconds in a day..


Remarks

As the date and time are in simple numeric format, arithmetic may be performed. The time portion is represented as a fractional day (0 represents midnight and 0.999999988426 represents 1 millisecond before the next midnight) allowing arithmetic both on days and on time; in other words a given date + 12 hours added to (say) a number of 1.5, representing 1 day and 12 hours, will yield exactly 3 days at midnight past the first date, as the time portions will add correctly to 1 additional day.


MsDate

The MSDATE function returns a Julian date representing the interpreted date as represented in a Quad (8-byte integer) value containing a MS SQL Timestamp value.


MSDATE(QuadVariable);


Parameters

              QuadVariable                    :             A Quad variable containing an MS SQL Timestamp.


Return values

The Julian date representation of the Timestamp provided. This is the native date format in LavaStream and in the Lava database.


Remarks

The Timestamp value presented would be obtained through an ODBC select from an MS SQL database, as well as some other commercial databases. If selected into a LavaStream variable, the corresponding field in the ROWTYPE structure should be specified of type QUAD.



See also

Specific Typecasting (Dates)



Variable functions


These functions operate on variables, and either return a derived value or modify the specified variable.


BITAND

Future provision - bitwise AND function.


BITOR

Future provision - bitwise OR function.


BITXOR

Future provision - bitwise XOR function.


Clear

The CLEAR procedure accepts as a single parameter any variable of any type, and clears (nulls) the variable.


CLEAR(Variable);


Parameters

              Variable                             :             Any variable


Return values

None


Remarks

The variable is clear (null, empty) after execution of the function. Any values contained in the variable are lost.


Dec

The DEC procedure accepts either a single parameter, being a variable, or two parameters, a variable and a decrement value. The variable is decremented according to the parameters specified.


Form 1 :

DEC(Variable);

Form 2 :

DEC(Variable, Value);


Parameters

Form 1 :

              Variable                             :             Any variable

Form 2 :

              Variable                             :             Any variable

              Value                                 :             Any numeric value or variable containing a numeric value


Return values

None


Remarks