PrimeBaseTalk Programmer's Guide

Copyright © 2001, SNAP Innovation Softwareentwicklungsgesellschaft mbH. All rights reserved.

The information contained in this document applies to:

Last major update to this document on November 16th, 1999.
 
 

Java and JavaScript are trademarks of Sun Microsystems, Inc.

All other product names mentioned herein are the trademarks of their respective owners.


Table of Contents

1. Introduction

2. The PrimeBase Virtual Machine

"Hosting" the PBVM
PBT as Middleware
PBT and DAL
Virtual Machine Sessions
3. Concepts
Getting Started
Submitting Requests
Compilation
Retrieving Output
Subprograms
Statements
Comments
Primitive Data Types
Arrays, Classes and Objects
Identifiers
Variables and Constants
Scope and Namespace
Operators
Flow Control
Procedures
Error handling
4. Variables
Constants
5. Primitive Types
BOOLEAN type
Integral types
Floating point types
Fixed point types
Date and Time Types
Textual types
BINARY types
6. Reference Types
Tests on References
7. Special Types
Generic
Null
Objname
8. Operators
BOOLEAN Operators
Comparison Operators
Arithmetic Operators
Bit-wise Operators
Data Type Conversion Operators
Unary Operators
Assignment Operators
Cursor-based Reference Operator
9. Procedures and Functions
Declaring a Procedure
A minimal Procedure Declaration
The maximal Declaration
Global Procedures
Function Procedures - with single result
Procedures with multiple results
Procedures with arguments and defaults
Scope
Static Statement Blocks
10. Flow Control
IF
SWITCH, CASE, DEFAULT
LABEL, GOTO
BREAK
CONTINUE
WHILE
DO WHILE
FOR
FOR EACH
11. Error Handling

12. Classes

Forward Declarations
Class Access
Inheritance
Final Classes
Abstract Classes
Class Redeclaration
Class Members
Access Operators
Static Members
Member Access
13. Objects
Constructor
Member Variable Initialization
Final Member Variables
finalize() as Destructor
clone()
getClass()
Member Procedures and Functions
Static methods
Abstract methods
Overloading
Overriding
Final Methods
Method Access
Reflection
14. Arrays
Array Methods
Numerically Indexed Array
Associative Array
15. Cursors

16. Garbage Collection

Explicit call
17. Concepts
The Data Access Language
Sessions - the DAL "runtime" Concept
System Architecture
18. Basic Elements
Data Type Conversions
Basic Elements
Functions Calls: f()
Cursor Based Reference: ->
 
19. Control Statements
DBMS Statements
DESCRIBE DBMS
DESCRIBE OPEN DBMS
OPEN DBMS
CLOSE DBMS
USE DBMS
Database Statements
DESCRIBE DATABASES
DESCRIBE OPEN DATABASES
OPEN DATABASE
CLOSE DATABASE
USE DATABASE
DESCRIBE TABLES
DESCRIBE COLUMNS
20. Basic Statements
Variable Manipulation
DECLARE
UNDECLARE
SET
Execute Statements
EXECUTE FROM
EXECUTE IMMEDIATE
EXECUTE FILE
Print Statements
PRINT
PRINTALL
PRINTCTL
PRINTF
PRINTINFO
PRINTROW
Error Handling
ERROR
ERRORCTL
21. Program Constructs
Conditional/Branch Statements
IF
SWITCH
LABEL
GOTO
BREAK
CONTINUE
Iteration Statements
WHILE
DO
FOR
FOR EACH
Procedure Statements
DECLARE PROCEDURE
RETURN
CALL
22. PBCTL - Configuring PrimeBase DAL Compatibility

23. Encrypting PrimeBaseTalk files
 
 

Appendices

A. System Variables
A.1 Format Control Variables
$ampm, $datefmt, $day, $decfmt, $moneyfmt, $month, $timefmt, $tsfmt
A.2 Constants
$false, $null, $true

Data Type Constants:

$BOOLEAN, $CHAR, $date , $DECIMAL, $FLOAT, $integer, $LONGBIN, $LONGCHAR, $MONEY, $smfloat, $SMINT, $time, $timestamp, $VARBIN, $VARCHAR
$sqlnotfound, $version
A.3 System Control Variables
$sqlcode, $sqlcode2, $switch
A.4 Cursor Control Variables
$aborttime, $colcnt, $cursor, $locktimeout, $maxrows, $rowcnt, $rowlocking, $rowsaffected, $rowsperpage
A.5 DBMS Lookup Variables
$dbmszone, $dbmsbrand, $dbmsprotocol
A.6 Login Information
$logintime, $connid, $user
B. Built-in Functions
B.1 String Functions
$format(), $hash(), $left(), $locate(), $ltrim(), $right(), $rtrim(), $substr(), $tolower(), $toupper(), $trim()
B.2 Variable Information Functions
$exists(), $len(), $scale(), $typeof()
B.3 Cursor Information Functions
$cols(), $collen(), $colname(), $colplaces(), $coltype(), $colwidth(), $currentrow(), $rows()
B.4 Cursor Manipulation Functions
$deleterow(), $insertrow(), $updaterow()
B.5 File I/0 Functions
$close(), $create(), $delete(), $fileexists(), $filestamp(), $getcwd(), $geteof(), $gettempdir(), $listdir(), $map(), $mkdir(), $nativepath(), $open(), $openreadonly(), $read(), $readline(), $rename(), $rmdir(), $seteof(), $write(), $writeline()
B.6 Miscellaneous Functions
$base64encode()$encrypt(), $errorstring(), $getenv(), $md5(), $now(), $ostype(), $putenv(), $sendmail(), $sendmailxt(), $yield()
C. Golfers Database




 
 

1. Introduction

PrimeBaseTalk (PBT) is an object oriented language specifically designed for the programming of "server-side" functionality common to intra- and internet Web sites.

The language includes the best ideas and concepts from 4 generations of languages, and combines them seamlessly and systematically. This includes:

The combination of such tools applied to any problem is extremely effective and allows for rapid application development.

PrimeBaseTalk is also DAL (Data Access Language) compatible and, as a result, supports code previously written to access the PrimeBase Database Server. In addition, it is "Java-like", making it easy for experienced Java programmers to use. This, and other factors have determined the design of PrimeBaseTalk, as will be discussed below.

Examples

Many of the examples in reference manual make use of a sample database, called the Golfers database. The tables and columns of the Golfers database are explained in detail in Appendix C.

So if you want to try any of these examples yourself you may want to copy and paste the Create Script into a file execute them in the PrimeBase Automation Client (PBAC) or the PrimeBase SQL Database Server console using the EXECUTE FILE command:

EXECUTE FILE "golfersdb.sql" LOCATION "c:\"; <press ENTER>
go <press ENTER>
Also make sure you open the Golfers database in PBAC or the server console prior to trying any of the examples contained in this reference manual. You do this by issuing the following:
OPEN DATABASE Golfers; <press ENTER>
go <press ENTER>
 




 
 

2. The PrimeBase Virtual Machine

The PrimeBase Virtual Machine (PBVM), is responsible for compiling and executing programs written in PBT. To do this the PBVM allows the creation of multiple independent "runtime environments", also known as sessions. Each session has its own global variables and execution thread, and runs independently of other sessions.

The PBVM supports various API's (Application Programming Interfaces) common to database applications, including DAL/DAM (the original Data Access Language and Data Access Manager API's from Apple™), ODBC (Open Database Connectivity from Microsoft™), JDBC (Java Database Connectivity from Sun™ Microsystems) and EOF Adaptor (Enterprise Objects Frameworks Adaptor from Apple).

The application uses one of these API's to create and destroy a session, submit and run a PBT program and receive output from the running program. Programs are submitted as a combination of text and BINARY data. The built-in compiler transforms the program into an internal "byte-code" form which can be executed by the Virtual Machine. A program running in a session may exit (normally or due to an error). After this point the execution thread of the session is idle, however the session remains, and a further program (sometimes more accurately refered to as a sub-program) may be submitted and executed.

During execution, classes are created and objects instantiated by the program. These objects and classes persists as long as the associated session remains. Subsequent programs can access objects and classes created by previously run programs.

This persistance is ideal suited for supporting Web-based applications, in which the state of the applications must be maintained on the server.

Additionally, the use of sub-program execution matches the way in which a Web-based application handles page requests. When a page request arrives, various sub-programs are submitted and executed in order to prepare the response. The result page is returned to the waiting browser, and in the meantime the sessions execution thread is idle.




 
 

"Hosting" the PBVM

Like the Java VM, the PBVM is implemented as a Shared Library, Shared Object or Dynamic Linked Library (depending on the platform) and therefore must be "hosted" by an application in order to do it's job. Any application that supports one of the API's mentioned above will do, but general purpose applications that are programmable using PBT are of particular interest. Two such applications are provided by SNAP:
PBT programs execute asyncronously and independently of programs in other sessions. The hosting application is responsible for assigning a thread for execution in each session. An application may choose to use one thread, however, in this case the application must schedule the execution in the various sessions itself.

Exactly how this is done depends on the API used. However, of all the API's mentioned above (DAL/DAM, ODBC, JDBC, etc.), the DAL API is the most suited to the internal workings of the PBVM, and is used by the PrimeBase Application Server and the PrimeBase Automation Client.

Other API's may limit the use of the PBT language in certain way due to limitations in their own specification. For example, the ODBC API only allows the programmer to use the SQL components of the PBT language.




 
 

PBT as Middleware

Using the PrimeBase Open Server Interface, PBT can act as middleware for diverse data sources, not just the PrimeBase Database Server. The Open Server Interface is based on the client/server model and can be used for remote execution (in the form of RPC - Remote Procedure Calls) or data exchange.

In order to support data transfer between a PBT program and an external data source an adaptor must be written that supports the PBOS Interface. The adaptor translates calls (SQL statements, procedure calls, etc.) from the PBVM, into calls to a 3rd Party DBMS (e.g. Oracle, Sybase etc.) or accesses data itself using, for example, XBASE or ISAM functions. Such an adaptor is compiled as a shared library and is also known as a PBOS Plug-in.

PBOS plug-ins for the most popular DBMS's are provided by SNAP, including Oracle, and ODBC data sources.

An application called the PrimeBase Open Server loads the plug-in and handles communication (local over a network) between the PBVM and the adaptor code. Alternatively a PBOS Plug-in can be loaded directly by the PBVM, eliminating the need for inter-process communication. This setup has obvious performance advantages, however, remote execution of a plug-in by the Open Server may be required for load distribution, or because as specific API required is only available on a particular machine, etc.

Whether the plug-in is loaded directly by the PBVM or loaded and hosted by the PrimeBase Open Server depends on the function of the adaptor and requirements of the system as a whole. How a plug-is deployed does not depend on how the plug-in is written, but only on the requirements of the system.
 
 




 
 

PBT and DAL

As mentioned above PBT provides a level of compatibility with the Data Access Language (DAL) from Apple™, which is also supported by previous Snap products. PBT was designed to eliminate ambiguities and add several new language features ranging from arrays to object oriented programming.

To maintain compatibility and also take advantage of the new features, PBT introduces two different language modes.

 

Extensions to DAL

In the following documentation, differences to the DAL mode are highlited with a special icon.

 
 
 

Comparison to other languages

Where appropriate, differences to other languages are also noted.




 
 

Virtual Machine Sessions

The Primebase Virtual Machine supports parallel execution through the session concept.

PBVM is usually accessed by some hosting application - for example the Primebase Application Server for web-based applications. The host application can open any number of simultaneous and independently executing sessions.

There is some basic means of sharing between sessions within the same virtual machine - objects allocated during execution of the "initialize.dal" procedure file are shared. This is not recommended for complex multi-tasking purposes, as there are no synchronization mechanisms built into the language. Especially the position of cursors is also shared.

Instead, the database integration provides a superior support for persistent data, locking strategies and transactions including rollback. All of this arbitrated between any number of independent hosting applications.




 
 

3. Concepts

This is an overview of the PrimeBaseTalk language. It will hilite the main concepts of the language and provide selected samples. Further detailed explanations and comparisons to other languages will follow in later chapters.




 
 

Getting Started

The hosting application has to open a connection to the PrimeBase Virtual Machine. The exact way is dependent on the API in use, and described in the "PrimeBase Virtual Machine Reference Manual". This connection is also referred to as session. The hosting application may open any number of additional independent sessions for separate execution.

Usually the session setup involves specifying a database machine for the default connection, although there may none, and additional parameters for user authentification ( user name, password ).

For the PrimeBase Application Server, all of this is controlled from outside using the first entry in the file "connect.def".

In the interactive mode of the PrimeBase Automation Server, it offers a list of all available connection definitions for manual choice.




 
 

Submitting Requests

The hosting application will submit any number of PBT statements and input parameters to the PBVM using the appropriate API calls, due to prepare a subprogram invokation. The parameters are either passed as literals embedded into the program code, or sent utilizing a dedicated API call.




 
 

Compilation

At the topmost level all PrimeBaseTalk subprograms are a collection of complete statements, terminated by ";". Only complete and valid statements are accepted by the compiler for one subprogram. If the compilation fails the whole subprogram is rejected.

After another API call, the combination of statements and parameters is then compiled by the PBVM into its internal bytecode representation, which is then executed.

The PrimeBase Application Server provides a large choice of different points where such requests might get placed, including web page preparation and explicitly tagged page sections.

The PrimeBase Automation Server intercepts lines containing the "GO" keyword and forces execution.




 
 

Retrieving Output

The results originating from the running subprogram are returned to the hosting application by explicit PRINT and PRINTF statements. In order to receive these results, the hosting application will apply polling calls, again dependent on the used API.

The PrimeBase Application Server will receive the output and deal with it according to several conventions. The simplest method will pass output into the program's own output stream.

The PrimeBase Automation Server also converts all received output to text and copies the result to its standard output.

 

Example

print "Hello, world";

Screen output:


Hello, world

 



 
 

Subprograms

At the topmost level all PrimeBaseTalk subprograms are a collection of complete statements, terminated by ";". Although the subprogram can get transmitted using several separate API call invokations, only complete and valid statements are accepted by the compiler. If the compilation fails the whole subprogram is rejected.

Besides simple statements which will get executed straight after compilation, PBT also knows statements to declare variables, procedures or whole object classes, and associate them with a name for later referral. These named entities will persist in the session across multiple different subprogram invokations, providing a convenient storage area.

The PrimeBase Application Server uses this to maintain its user session state across multiple page invokations, associated with a single user.




 
 

Statements

Most PrimeBaseTalk statements are in a functional notation similar to C and Java. For database integration, several mighty (and therefor verbose) additional statements also integrate a superset of SQL.




 
 

Comments

Any text enclosed within "/*" and "*/" is considered a comment and therefor ignored for compilation.

There is also a new provision for single line comments - text after the "//" token is skipped until the end of line.
 
 

 

Hint

PBT comments do nest. This makes them a partial replacement for a preprocessor as known from the C language. This approach avoids the complexity because of which the C preprocessor was omitted from the Java language.

To comment out any range of code, including comments or not, just enclose it into another comment.
 


 
 
 

Hint

Some editors support balancing of brackets - exploit them inside your comments.

 
 
 

Example

/* { A Comment with a balanced bracket.
Some inactive code here.
/* an older, nested comment. */
Some more inactive code here.
} */
// the closing bracket above may get found by some editors
print "Hello, world.";




 
 

Primitive Data Types

PrimeBaseTalk provides a rich set of primitive data types, with the speed benefit of native execution.

These include specialized types for date and time arithmetic, arbitrary size fixed point arithmetic based on BINARY coded DECIMAL (BCD) and several types for textual and BINARY data.

All primitive data types and operations support the explicit $NULL (mark) value as it is required for basic data types of relational databases.

Values of the primitive types are kept read only and therefor secured against modifications in place. All operations on them work on temporary expressions, the results have to be assigned to a variable to change it.

Literals represent a constant value of a certain data type. The characters that make up a single literal may not be separated by space, tab or end of line characters. Literal values may be placed directly in expressions and queries in PBT programs.

Besides sending literals embedded into query code, the PrimeBase VM provides dedicated API calls for direct submission of values.

Maintained at the database engine there is an additional level of data types, with stronger type checking and several additional features (case insensitive comparisons etc.) up to composite data types.




 
 

Arrays, Classes and Objects

In addition to the builtin primitive data types, PBT provides native support for classes and objects, with some special classes (Array and Cursor).

All of these data types are handled using object references, in order to implement an object model comparable to Java.

Arrays are either preallocated and numerically indexed or dynamically allocated as associative array, similar to Java's Dictionary class.

Cursors are used to store result sets of database operations.

The data types are described in detail in a following section.




 
 

Identifiers

The PBT language is case insensitive for statements, identifiers and keywords, with identifiers having a maximum length of 31 characters.

The first character of an identifier is drawn from the 26 alphabetical characters and the "_" underscore. The additionally possible "$" dollar sign is reserved for system functions.

The following identifier characters may again use the 26 alphabetical characters with addition of digits, the "#" hash mark and the "_" underscore, but not the dollar sign.
 
 

 

Note

The keywords "new", "this", "super" are especially reserved because they have a different meaning even inside expressions.

Other keywords include "final", "abstract", "class", "extends", "public", "protected", "private" and "static".
 




 
 

Variables and Constants

Variables are slots used to hold any value, associated with an identifier (name). Their type is predefined at the time of declaration, making them available for further access.

PrimeBaseTalk has a new concept of dynamic constants. These are similar to traditional variables, allowing to take full advantage of all language features during initialization. From then on they are protected against changes.




 
 

Scope and Namespace

With DAL, all kinds of entities shared the same global namespace. PrimeBaseTalk continues to support this global namespace, but provides alternatives.

There is also a local scope during execution of procedure calls, for use by temporary "local" variables.

The local scope is shared within one procedure call - variables declared persist until exit of the procedure or explicit undeclare, even when they are declared in a contained block.

To reduce the probability of collisions in the single global namespace, PrimeBaseTalk now also supports additional namespaces, within the scope of classes.
 
 

 

Note

The package concept is currently not supported.

 
 
 

Note

Classes are declared and defined in one consecutive code sequence, similar to Java.

Because of the use of classes for namespaces, the namespaces are not open for extensions.
 

For execution of immediate statements there is an anonymous "static" block limiting the variable lifetime of temporary variables.




 
 

Operators

SQL allows both '=' and '==' for the equality comparison, and '=' for assignments.

To resolve the ambiguity between assignment and comparison, the PrimeBaseTalk language introduces ':=' as assignment operator. Only in the DAL compatibility mode, the previously used '=' is still available.

Class members are accessed with the operator ':' instead of '->' or '::' or '.'




 
 

Flow Control

PrimeBaseTalk provides standard flow control for conditional execution and iteration (loops) with additional support of database specifics.




 
 

Procedures

The DAL language already supported procedural programming with some unconventional additions. These advantages persist but are integrated into a new level of object oriented programming.




 
 

Error handling

Errors are handled using the traditional methods of DAL. In exceptional situations ranging from "division by zero" to "transaction timed out", an error code is made available to the handling program. Dependent on further settings, execution is returned to the program hosting the PBVM, or the session itself tries to handle the problem.

A number of additional information is available through several system variables and functions.




 
 

4. Variables

Variables and constants are declared either in the global namespace, as member variables of classes, or dynamically during execution of procedures. These concepts are also described in detail later.

The variable declaration reserves a storage area and associates it with the given name and specified data type. Variables with one data type will only accept values of this data type. Some data types are also automatically converted.

Unless given a default value on initialization, newly declared primitive type variables are tagged as "unitialized", therefor preventing use of any random value. Further explicit initialization is possible within the declaration, assigning any expression. Reference variables are initialized with the empty reference $NULL unless an explicit initialization is provided.

The value stored in a variable is available for multiple use in any expression, until it gets replaced with a new assignment or the variable gets removed - with an explicit undeclare in global or local scope, or by redeclaring it as something else with the same name.
 
 

 

Example

declare INT a;
integer b := 1;
// print a; -- would fail because a is uninitialized
a := b + 1;
undeclare b; // now b is gone
declare VARCHAR a = "x"; // replacing old a




 
 

Constants

Named constants are not supported. Instead PBT provides a runtime protection against overriding variables declared with the final identifier. The advantage is a larger flexibility for the initialization of the constant - even from the result of a function call.

Global final variables are not protected against redeclaration.




 
 

5. Primitive Types

For use by variables and temporary expressions, PrimeBaseTalk supports a variety of data types which either are treated as atomic value or refer to a larger object. Data types working with concrete values are either called "primitive types" or, especially in context of relational databases, "basic types".

Primitive values are "atomic" because they are not modifyable in place. A text or numeric value stored in a variable will remain the same, until the containing variable explicitly gets assigned a new value.

The primitive types have an associated numeric type code, wich is internally returned by the functions $typeof() and $coltype(), and is also used by several database related statements.
 
 

 

Note

The type codes used by the PrimeBase Virtual Machine are those of the CL1 API. If you access the PrimeBase Virtual Machine using a different API, for example Apple DAM or ODBC, you will encounter different type codes.
See also:

$typeof(), $coltype(), printctl, describe columns, describe dbms
 
 

 

Note

Some extended functionalities, e.g. of domains are not supported beyond the database engine.
The following sections describe the primitive types in detail.




 
 

BOOLEAN type

The BOOLEAN data type is expected by control statements like if and while.

An implicit conversion to BOOLEAN is only available from integral, floating point and numeric types - textual and reference types are excluded. BINARY types have additional size constraints for a successful conversion.

The literals $false, $true and $maybe represent the different BOOLEAN values.

The BOOLEAN $maybe is mainly produced by a comparison with one of the operands being $null.
 
 

 

Example

print $typeof($true), $BOOLEAN;
print $true, $false, $maybe;
print (VARCHAR) $true, (VARCHAR) $FaLsE, (VARCHAR) $maybe;
print (BOOLEAN) "$maybe"

Screen output:


1 1
$TRUE $FALSE $MAYBE
$TRUE $FALSE $MAYBE
$MAYBE




 
 

BOOLEAN Values: 3-Valued Logic

Unlike C which uses the value zero to represent FALSE and non-zero to represent TRUE, PBT uses a special BOOLEAN type value. A BOOLEAN value can be one of 3 logical values: $true, $false or $maybe. The $maybe value is the result of a comparison with an unknown value ($null).

Evulation is done according to the following logic tables:
 
 

 
AND $true $false $maybe
$true $true $false $maybe
$false $false $false $false
$maybe $maybe $false $maybe

 
 
 
OR $true $false $maybe
$true $true $true $true
$false $true $false $maybe
$maybe $true $maybe $maybe

 
 
 
NOT  
$true $false
$false $true
$maybe $maybe




 
 

Conditional Expressions (if, while, etc.)

Condition expressions such as those in the if, while and do statements, are only executed if the result is $true (not in the case of $false or $maybe). The conditional expression in these statements is automatically converted to a BOOLEAN value.

Because of 3-valued logic used, conditional expressions can have some surprising effects. For example:
 
 

 

Example

procedure test(a)
argument integer a;
{
        print "Testing the value ", a;
        if( a==1 )           print "The value is equal to one";
        if( (a==1)!=$false ) print "The value is equal to one or unknown";
        if( a!=1 )           print "The value is not equal one";
        if( a==1 or a!=1 )   print "The value is either equal or not equal";
          else               print "Two valued logic fails!";
        if( a is null )      print "The value is null";
        if( a is not null )  print "The value is not null";
print;
}
end procedure test;

test(1);
test(2);
test($null);

Screen output:


Testing the value  1
The value is equal to one
The value is equal to one or unknown
The value is either equal or not equal
The value is not null






Testing the value  2
The value is not equal one
The value is either equal or not equal
The value is not null






Testing the value  $NULL
The value is equal to one or unknown
Two valued logic fails!
The value is null




 
 

Integral types




 
 

tinyint

Tiny integers have the characteristics of the unsigned 8 bit integer data type know from the C language. Their value ranges from 0 to 255.
 
 
 

Example

tinyint t := 1;
print $typeof(t), $tinyint, $len(t);
print tinyint 0x7F, tinyint 0x80, tinyint 0xFF;

Screen output:


20 20 1
127 128 255




 
 

SMALLINT / SMINT

Small integers are signed short (16 bit) integer ranging from -32768 to 32767.
 
 
 

Example

SMALLINT s = 1;
print $typeof(s),$SMALLINT, $len(s);
print SMINT 0x7fff, SMINT 0x8000;

Screen output:


2 2 2
32767 -32768




 
 

INTEGER / INT

The integer data type is equivalent to signed long (32 bit) integer ranging from -2147483648 to 2147483647.
 
 
 

Example

print $typeof(1),$integer, $len(1);
print INT 0x7FFFFFFF, (INT 0x7FFFFFFF) + 1;

Screen output:


3 3 4
2147483647 -2147483648

 
 
 
 
 

Hint

A 64 bit integer data type is not supported, but you can achieve even better precision and range by using the "DECIMAL" fixed point data type.

 
 
 

Note

In parameter matching for overloaded functions (described later), all integral types are considered equal.




 
 

Floating point types

Floating point values support a larger numerical range, but at the cost of less precision. This is achieved by reserving a part of the internal representation for an exponent.
 
 
 

Note

In parameter matching for overloaded functions (described later), all floating point types are considered equal.




 
 

SMFloat

A 4 byte floating point variable.




 
 

FLOAT

An 8 byte floating point variable.




 
 

Literals

Floating point literals are expressed in exponential form, with a DECIMAL point and a signed exponent of an 'e' or 'E'.
 
 
 

Example

print $smfloat, $FLOAT;
print 0.123e12, 3.141E0, 100.00001e-14, -5.6789E+8;

Screen output:


4 5
1.23E+11 3.141E+00 1.0000001E-12 -5.6789E+08




 
 

Fixed point types

The fixed point variables are implemented on base of BINARY coded decimals (BCD).

This means their internal representation is an almost arbitrarily long string of DECIMAL digits, two of each are squeezed into one byte value.
 
 

 

Hint

You can view the internal format of BCDs by converting to BINARY.

 
 
 

Example

printf("%x\n",VARBIN DECIMAL[10,2]  1234.56);
printf("%x\n",VARBIN DECIMAL[10,2] -1234.56);

Screen output:


000123456c
000123456d
Conversion between text and fixed point is controlled by the format variables $decfmt and $moneyfmt. $moneyfmt usually includes the currency symbol.




 
 

DECIMAL

DECIMAL literals are expressed using an optional sign, digits and one contained DECIMAL point ('.').
 
 
 

Example

print $decfmt, DECIMAL[10,4] 1234.56;

Screen output:


9,999.9 1,234.56




 
 

MONEY

MONEY literals are specified with a leading dollar ('$') sign, then optional sign, digits and a DECIMAL point ('.').
 
 
 

Example

print $moneyfmt, MONEY[10,4] 1234.56;

Screen output:


$ 9,999.9 $ 1,234.56




 
 

Date and Time Types




 
 

Date

Date values are internally represented by single bytes for date and month, and a short integer for the year. The maximum valid year is 9999 though.

The $datefmt, $day, $month system variables control conversion from and to text.
 
 

 

Hint

By assigning partial control strings to $datefmt, you can extract any parts of the date by converting it to text.
In arithmetical expressions, the numeric value 1 is equivalent to one day.
 
 
 

Example

print print (date) "1/1/1999" + 1;

Screen output:


01/02/1999




 
 

Time

Time values are internally stored as one byte each for hour, minute, second and hundreths of second.

The $ampm and $timefmt system control variables control conversion from and to text.




 
 

Datetime, Timestamp

The datetime data type combines date and time into a single value.

Timestamp is only an alternate name for the same data type.
 
 

 

Hint

The function $now() yields the current date and time. The keyword NOW is also used in the database statement CREATE DEFAULT




 
 

Date and Time Literals

Date and Time constants are best submitted in their native format. If the hosting application does not support this, they must be supplied according to the currently active conversion format.

The conversion format variables are accessible for read and write, therefor you can save them into a temporary variable, set them to your expected format and later on restore the value.
 
 

 

Example

print $datefmt;
print date "1/1/1999";

Screen output:


MM/DD/YYYY
01/01/1999




 
 

Textual types

In addition to the direct support of textual data types, there is a rich library of string functions.

Most string operations are 1 based, 1 is the position of the first character.
 
 

 

Hint

You can use the PBT function $format() (which is an equivalent to sprintf()) to interpret C escapes and apply formatting to additional parameters.

There is also a function called PRINTF(), which uses the same parameters as $format() and which causes direct output instead of returning a string.
 




 
 

VARCHAR

The maximum length of character based values, either for variables or expressions (not for database table columns!) in string operations, are as follows:
 
 
 
Date Type Length in Bytes Length in Characters
CHAR 1 048 576 1 048 576
VARCHAR 65 536 65 536
UNICODE 1 048576 524 288

 
 

Note

The underlying database system might impose stronger restrictions on these data types!




 
 

CHAR

The CHAR data type is used for fixed length strings. Shorter strings are padded with trailing spaces (ASCII character 32).

For this reason trailing spaces are ignored for all string comparison operations.
 
 

 

Example

print $CHAR, "A" == "A    ";

Screen output:


9 $TRUE




 
 

LONGCHAR

Beyond the size limit of 65 535 characters for a VARCHAR, you have to use the LONGCHAR data type.

Most string operations work for LONGCHAR.
 
 

 

Example

print $LONGCHAR;

Screen output:


14




 
 

UNICODE

UNICODE is an ISO standard for encoding characters, with support of all written languages of the world. In version 2.0 of the UNICODE standard (version supported in PrimeBase) 16 bit encoding is used to encode up to 65 536 different characters.

More information is available at www.unicode.org

The maximum length of UNICODE strings is 524 288 characters.
 
 

 

Example

print $typeof(UNICODE "");

Screen output:


27

 
 
 

Note

For correct working of the UNICODE data type, the "UNICODE" folder must be present inside the Setup folder.

Some string functions ( $toupper, $tolower) currently don't expect UNICODE. They convert to VARCHAR and assume the Macintosh Roman character encoding.
 




 
 

Literals

Character literals are a string of characters, enclosed either in single or double quotes.

The literal may contain the same quote by duplicating it, rather than escaping it with a backslash as in C.

The $format() function supports C-like escape sequences.
 
 

 

Example

print $format("x=%d\ny=%d\n%s",1,2,"Hello, ""YOU!""");

Screen output:


x=1
y=2
Hello, "YOU!"




 
 

BINARY types

Literals for BINARY types are specified in hexadecimal notation which produces a VARBIN.

The BINARY data types, especially VARBIN, can be used as intermediate, raw data type.
 
 

 

Example

print INT 0x12345678;
printf("%x",VARBIN "1234");

Screen output:


305419896
31323334




 
 

VARBIN

The VARBIN data type is the default for short BINARY data.

VARBIN is often used as intermediate data type when converting between the raw representations of incompatible data types.
 
 

 

Example

print $len(0x01), $typeof(0x01), $VARBIN, tinyint VARBIN "A", VARCHAR 0x40;

Screen output:


1 13 13 65 @




 
 

LONGBIN

This is the BINARY Large OBject (BLOB) variant of the BINARY data type.

In database tables LONGBIN fields are stored as a separate file, with only a reference stub of 64 bytes counting into the maximum record size.
 
 

 

Example

print $LONGBIN;

Screen output:


15




 
 

BINARY

The BINARY data type is the fixed-size variant of the VARBIN data type, similar to CHAR versus VARCHAR.
 
 
 

Example

print $typeof(BINARY 0);
printf("%x\n",BINARY[10] 4660);

Screen output:


25
00001234000000000000




 
 

Literals

BINARY strings are submitted in either of two hexadecimal notations.

They should contain an even number of hex digits. ( 0123456789ABCDEF )
 
 

 

Example

print 0x28736f6D65, 0X726177, X"6461746129";

Screen output:


(some raw data)




 
 

6. Reference Types

The PBT object model is similar to Java, with some shortcuts. It is described in detail later.




 
 
 
 

Tests on References

There are no default comparison operators between object references. Currently the only legal operations are NULL tests:
 
 
 

Example

class A {};
A aa = new A();
print   aa is null, aa is not null;
Members of referenced objects are accessed using the ':' operator.




 
 

7. Special Types

This section covers related concepts which are not represented as own type.




 
 
 
 

Generic

Variables declared as generic are containers which accept values of any data type, both primitive and reference types.

The currently assigned data type is determined by the $typeof() function.

Generic is not available as data type for database fields. You may use the VARBIN type instead, because it is generically convertible.




 
 

Null

Null is used for two different concepts.

In the context of relational databases it stands for missing (unknown) or inapplicable information. This is supported by all primitive data types.

Contrary to database fields, there is no way to declare a variable to be NOT NULL.

In the context of object oriented programs $null stands for an empty reference.

The $null constant
$null has no data type on its own (it translates to VARCHAR by default). In assignments and expressions $null is compatible with all other data types.

$null only exists with the dollar sign. But for compatibility reasons, there are also some special syntactic forms originating from SQL, which require the keyword NULL instead.

Sticky NULLs
Expressions involving $null usually yield $null. Prominent exceptions are the $len() function (yields zero) and comparison operations (producing booleans).

Therefor care must be taken whenever nulls could be introduced, for example through the database schema.
 
 

 

Example

integer i = $null;
print $typeof($null), $VARCHAR, $typeof(i), i is null, $len(i), 1+$null;

Screen output:


12 12 3 $TRUE 0 $NULL




 
 

Objname

The object name data type is used in database statements and when accessing cursors. It does not work as pointer to member for PBT objects.

There is also no support for objname by the database engine.
 
 

 

Example

print $typeof(objname "name");
describe databases; fetch;
print ->name, $cursor->(objname "name");

Screen output:


17
pbedemo pbedemo




 
 

8. Operators

In expressions, operators are used to manipulate or combine operands (variables, literals or other expressions).




 
 

BOOLEAN Operators

The operators AND, OR and NOT operate on BOOLEAN values, and return a BOOLEAN value.

Note that, unlike for example in the C programming language, both sides (operands) of the operators AND and OR are evaluated regardless of the outcome of the evaluation of the first operand. This is relevant if the calculation itself has a sideeffect, for example in a procedure call.
 
 

 

Example

BOOLEAN initialized = $true;
BOOLEAN printed = $false;
IF ( initialized AND NOT printed )
{
 PRINT "Now it is being printed.";
} ELSE {
 PRINT "ERROR: Can't print, it probably has not " +
       "been initialized yet.";
}


Screen output:


Now it is being printed.




 
 

Comparison Operators

The comparison operators and the "null-test" operator (IS NULL), all produce BOOLEAN values. Arguments may be values of any data type (as of PrimeBase 3.5 also CURSOR).

In comparisons, if one (or both) of the operands are $null, the result is the BOOLEAN value $maybe.

Comparison operators supported by PBT are

'==', '<>', '<', '>', '<=', '>=', '!='
and the unary operators IS NULL and IS NOT NULL.

In addition, the DAL compatibility mode supports the equality operator '='.
 
 

 

Example

BOOLEAN itIsRaining = $true;
IF ( itIsRaining == $true ) {
  PRINT "Too bad, it is raining.";
} ELSE {
  PRINT "Hey, it is not raining.";
}

/* Or equivalent: */
IF ( itIsRaining ) {
  PRINT "Too bad, it is raining.";
} ELSE {
  PRINT "Hey, it is not raining.";
}

/* And a different example: */
INTEGER anIntValue = 10;

IF ( anIntValue != 10 ) {
  PRINT "The value has not been properly assigned " +
        "to the variable!";
} ELSE {
  PRINT "The value has been properly assigned to the " +
        "variable.";
}

Screen output:


Too bad, it is raining.
Too bad, it is raining.
The value has been properly assigned to the variable.

 
 
 

Warning

Note that trailing spaces are ignored when comparing strings,
meaning that 'a ' == 'a    ' evaluates to BOOLEAN true.




 
 

Arithmetic Operators

The following arithmetic operations are supported by PBT expressions: addition (+), subtraction (-), multiplication (*), division (/) and remainder (%).
 
 
 

Example

PRINT "The remainder of 10 / 3 is", VARCHAR( 10 % 3 );

Screen Output:


The remainder of 10 / 3 is 1
Addition operators and Date, Time
Addition of plain date and time values won't yield the intended results. Instead, the date has to be converted to a datetime.
 
 
 

Example

date d = $now(); datetime dt = d; time t = $now();



print d+t, dt+t, $now();



02/02/1994 05/12/2000 17:34:05.00 05/12/2000 17:34:05.42
The conversion from VARCHAR is useful to compose date and time values from their components.
String Concatenation
The addition (+) operator may also be applied to character string values. The character string values are concatenated, and the result is a VARCHAR value.
 
 
 

Example

PRINT "Hello" + " " + "world" + "!";

Screen Output:


Hello world!




 
 

Bit-wise Operators

The bit-wise operations are those familiar to C and Java programmers. Shifting operators are currently not implemented.
 
 
 

Example

PRINT "255 & 127 =", VARCHAR( 255 & 127 );

Screen Output:


255 & 128 = 127




 
 

Data Type Conversion Operators

PrimeBaseTalk supports extensive data type conversion. Conversion to character string values is controlled by the various Format Control Variables.

Additionally there is an explicit syntax for conversion between other data types.

The following sample uses the function now() to get the current time with the type of datetime. The first cast extracts the time part, the second part converts it into a VARCHAR, using the format control variable $timefmt.
 
 

 

Example

print (VARCHAR) (time) $now();

Screen output:


23:48:08.59
The data type used for the conversion may specify size and scale as described for the various data types.

In DAL compatibility mode the old syntax without explicit round brackets is still valid. In addition, it is not any more required to enclose the intermediate result of the first cast in brackets.
 
 

 

Example

print tinyint VARBIN $maybe;

Screen output:


2
Numerical values not equal to zero are considered $TRUE in BOOLEAN promotion.

DECIMAL[] used to be a valid type for declarations and casts to the DECIMAL data type. Use DECIMAL[,] now to prevent collisions with the array mechanism.
 
 

 

Example

print (DECIMAL[10,2]) 0, DECIMAL[10,2] 0;

Screen output:


0.0 0.0




 
 

Unary Operators

The unary operators supported by PBT are unary-affirmation (+), unary-negation (-), and unary bitwise NOT (~).

Permissible operands are all numeric types (TINYINT, SMINT, INTEGER, DECIMAL, MONEY, SMFLOAT, FLOAT), and BINARY values (VARBIN).

operator ++ and --

These are currently no true operators, but instead extensions of the set statement, and limited to the postfix variant.
 
 

 

Example

INT i = 1;
set i++;
i++;
print i;
3

 
 
 

Example

/* these would all fail:
++i;
print i++;
MyClass:myVar++;
*/




 
 

Assignment Operators

Assignments change a slot referenced by some expression, on the left side of the assignment operator, to contain a new value provided by another expression, on the right side of the assignment operator.

The assignment operator has two equivalent variants: ':=' and '='.

':=' is the preferred notation required by PrimeBaseTalk mode programs. PrimeBaseTalk mode will reject the operator '='.

'=' is deprecated and only supported in DAL compatibility mode programs. It has the severe problem that the SQL language also allows the operator '=' for equality comparison. The operator ':=' is therefor recommended for DAL compatibility mode too.

Expressions using the operator = in an intermediate result are interpreting it as comparison operator.
 
 

 

Example

INT a := 1;
print (a =  2), a;
print (a == 2), (a := 3), a;

Screen output


$FALSE 1
$FALSE 3 3
There are no arithmetic assignment operators ( a+=7 ... ).




 
 

Cursor-based Reference Operator

The '->' operator is used to access values of the current row of a CURSOR rowset. The column may be specified using the column alias, an INTEGER literal representing the column ordinal number or a variable containing one of these two.

If the variable is of type INTEGER it is the column ordinal number, and if it is of type OBJNAME it is the column alias.
 
 

 

Example

select 1 as a, 2 as b into myCursor;
fetch of myCursor;
declare objname a = "b";
print myCursor->a,myCursor->:a;

Screen output:


1 2




 
 

9. Procedures and Functions

Procedures and functions allow to bind frequently used program code to a name. These are then available for execution in subsequent program code, even in the same subprogram.




 
 

Declaring a Procedure

Procedures are declared on a per session basis. They are not stored inside the database - the Primebase Virtual Machine does not require a database connection for its work.

As with all identifiers, the name of procedures is limited to 31 characters, and case insensitive.
 
 

 

Hint

Procedures declared on startup of the first session, within the file "initialize.dal", are shared between all additional sessions in the same PrimeBase Virtual Machine.

This feature should be avoided during development, so you don't experience replaced code.
 




 
 

A minimal Procedure Declaration

Simple procedures have no arguments, or only arguments declared with a default. They may get invoked by simply writing their name as a statement. It is also possible to apply the more verbose syntax of complex procedures.
 
 
 

Example

PROCEDURE mySimpleProc()
returns VARCHAR;
{
        printf("Hello, world\n");
        return "ABC";
}
END PROCEDURE mySimpleProc;
Unhandled results are silently ignored.
 
 
 

Example

mySimpleProc;
mySimpleProc();
call mySimpleProc();

Screen output:


Hello, world
Hello, world
Hello, world

 
 
 

Note

It is not possible to omit the round brackets for member function calls.




 
 

The maximal Procedure Declaration

In addition to the previous sample, procedures can have multiple arguments and/or multiple results.
 
 
 

Example

DECLARE GLOBAL PROCEDURE myProcedure(a1,a2,a3)
RETURNS VARCHAR,INTEGER;
ARGUMENT VARCHAR a1 = "1";
ARGUMENT GENERIC a3 := $NULL;
{
        PRINT "1", a1;
        PRINT "2", a2;
        PRINT "3", a3;
        RETURN a1,7;
}
END PROCEDURE myProcedure;
The DECLARE keyword is optional for procedure declarations.

The GLOBAL keyword is optional. It is only important when you use the "execute file" statement from within an old style global procedure. Procedures declared within that file are only temporarily available, within the scope of that procedure.

The optional RETURNS clause may declare multiple results by type. These are returned in parallel, not alternatively.

The order of the arguments in the parameter list determines the order of binding on invokation. The order may be different from the following parameter declarations.

For each parameter there can be a parameter declaration using the ARGUMENT. If a parameter is missing from the parameter declarations, it is assumed to be of type GENERIC.

In the parameter declaration, you can optionally provide a default expression. In DAL mode, both assignment operators are available for that purpose. In PBT mode (within class declarations), you have to use the ':=' operator.

Finally, you have to copy the exact procedure name into the END PROCEDURE part of the declaration.

If the parameter was declared with a default value, it is optional in the call. To skip optional parameters and override others, use an empty expression.
 
 

 

Example

// equivalent assuming previous procedure declaration:
myProcedure(,2);
myProcedure("1",2,$null);




 
 

Global Procedures

For PBT mode subprograms (class methods) all procedures created by "execute file" are declared globally by default. Only when you use "execute file" from within DAL compatibility mode non-global procedures created there are purged, when leaving the scope of the "execute file" statement.
 
 
 

Example

// file myProc
PROCEDURE myProc() { print "2"; } END PROCEDURE myProc;
// code
PROCEDURE myProc() { print "1"; } END PROCEDURE myProc;
PROCEDURE aTest()
{
 print  "DAL mode";
 myProc;
 execute file "myProc.dal";
 myProc;
}
END PROCEDURE aTest;
aTest;
myProc;

class X {
public static PROCEDURE aTest()
{
 print  "PBT mode";
 myProc;
 execute file "myProc.dal";
 myProc;
}
END PROCEDURE aTest;
};
X:aTest();
myProc;

Screen output:


DAL mode
1
2
1

PBT mode
1
2
2




 
 

Function Procedures - with single result

Procedures with one result are allowed inside expressions.

For methods, inside class declarations, there is a new alternate function declaration syntax.
 
 

 

Example

print mySimpleProc() + "DEF";

Screen output:


Hello, world
ABCDEF




 
 

Procedures with multiple results

It is possible to return a large number of result expressions in parallel, instead of the usual maximum of one.

This is also a alternative for the "call by reference" notation of other languages which silently modifies given parameters.
 
 

 

Example

procedure multipleReturn()
returns VARCHAR, integer;
{
        return  "Test", 3;
}
procedure multipleReturn;
Procedures with multiple results are called with the explicit call syntax:
 
 
 

Example

generic a,b;
call multipleReturn() returning a,b;
print a,b;

Screen output:


Test 3




 
 

Procedures with arguments and defaults

You can specify a matching default expression for each argument. The default is taken as a replacement value for the argument, when the calling code did not provide enough parameters or omitted the matching parameter.
 
 
 

Note

The default is evaluated only when no other value is specified.

 
 
 

Example

procedure tick()
returns integer;
{
        print "tick";
        return  1;
}
end procedure tick;

procedure timed(a1,a2)
argument time a1 = $now();
argument integer a2 = tick();
{
        print   a1;
        print   a2;
}
end procedure timed;
timed;
timed(,2);

Screen output:


tick
11:06:38.84
1
11:06:38.92
2




 
 

Scope

Parameters and variables declared within procedures have a local scope. That is, they expire when the procedure is left.




 
 

Static Statement Blocks

Another addition to the DAL language is the introduction of static statement blocks. These fulfill two purposes:

The statements are executed in PBT mode rather than in DAL compatibility mode.

The statement block is a separate scope for variable declaration.
 
 

 

Example

integer a = 1;
if( $true ) static {
        integer a := 12;
        static {
                integer a := 123;
                print a;
        };
         print a;
};
print   a;

Screen output:


123
12
1
As you see from the example, it is possible to nest the static blocks.
 
 


 
 

 

Note

Non-static blocks executed at global level or within other blocks of procedures or functions do not introduce a new scope.

 
 
 

Example

INT a = 1;
if( $true ) {
        INT a = 2;
}
print a;

Screen output:


2




 
 

10. Flow Control

PrimeBaseTalk provides the standard statements for flow control.




 
 

IF

The IF statement evaluates the given expression. If the value or its BOOLEAN promotion is the BOOLEAN $true, the following statements gets executed. Otherwise an other statement after an optional ELSE keyword is executed.
 
 
 

Example

if( $true ) print "yes";
else print "no";
if $null is null print "yes"; else print "no";

Screen output:


yes
yes




 
 

SWITCH, CASE, DEFAULT

The SWITCH statement evaluates the given expression, which might be of any PrimeBaseTalk primitive type, including textual types.

Execution is resumed at the first CASE literal matching the value, and continues till the end of the SWITCH statement or the first BREAK encountered, whichever comes first.

The DEFAULT case is used if no direct matching literal is found. It can be located anywhere inside the SWITCH statement, even preceding further CASEs.

Neither duplicate CASEs with the same literal nor multiple DEFAULTs are permitted within one SWITCH statement.
 
 

 

Example

switch( "A" ) {
case "A": print "fine";       break;
case "B": print "bad";        break;
case "C": print "too bad";    break;
default:  print "don't know"; break;
case "E": print "easy";       break;
);

Screen output:


fine
The SWITCH statement can be used to deal with generic parameters to procedures.
 
 
 

Example

generic aValue := "A";
switch( $typeof(aValue) ) {
case $CHAR:
case $VARCHAR:
case $LONGCHAR:
  print """", aValue,""""; break;
default:
  print VARCHAR aValue;
);




 
 

LABEL, GOTO

The LABEL statement indicates a position in code that can be addressed by the GOTO statement.

The GOTO statement jumps to the statement following the LABEL statement with the same name. The label must be in current scope (procedure or global).

A GOTO statement may jump out of FOR, FOR EACH, WHILE, DO and SWITCH statement, to break the flow of execution. It is not recommended to jump into the middle of these statements.
 
 

 

Example

GOTO ComeHere;
PRINT "A";
LABEL ComeHere:
PRINT "B";

Screen output:


B




 
 

BREAK

The BREAK statement is used to exit the current loop (WHILE, DO, FOR, FOR EACH) or SWITCH statement.

When a BREAK appears within nested loops, or SWITCH statements, it will cause the processing of the innermost loop (or rather, SWITCH) to break. It is not possible to cause a multilevel break in a single statement.




 
 

CONTINUE

The CONTINUE statement interrupts the flow of the body of a WHILE, DO, FOR, FOR EACH statement, thus causing the remainder of the current iteration of that statement to be skipped.

Execution continues with the loop control expression (for WHILE or DO) or with the loop-reinitialiser (for FOR), or with fetching of the next row (for FOR EACH).
 
 

 

Example

INT i;
FOR( i:=1; i<5; i++ ) {
 if( i==3 ) continue;
 print i;
};

Screen output:


1
2
4




 
 

WHILE

The WHILE statements repeatedly evaluates the given expression. If this expression yields or is converted to $true, the next statement is executed. Otherwise the loop is ended.
 
 
 

Example

integer  secs := 10;
datetime till := $now() + secs;
print "Let's sleep for", secs, "seconds!";
while( till > $now() ) {
  $yield();
}
print "done.";

Screen output:


Let's sleep for 10 seconds!


done.




 
 

DO WHILE

The DO statement executes the contained statement repeatedly until the post-test evaluates to $false.
 
 
 

Example

BOOLEAN failed;
do { failed := trySomeThing(); } while failed;




 
 

FOR

The FOR statement is used to control a loop with dependence on a control variable.

The first expression in the following round brackets is an assignment used to initialize the control variable.

The second expression is the loop condition. The loop will repeat the following statement as long the second expression yields $true.

The third expression is another assignment, used to update the control variable after the following statement was executed.
 
 

 

Example

INT i;
for( i:=0; i<2; i++ )
  print i;

Screen output:


0
1




 
 

FOR EACH

The FOR EACH statements is a special loop for the result sets of database operations.

Its control variable is a cursor.
 
 

 

Example

cursor x;
describe databases into x;
for each x
  printrow x;

Screen output:


Model
Master




 
 

11. Error Handling

The 'errorctl' statement sets an internal control variable - execution continues after the error situation or is returned to the program hosting the PBVM.

For both cases there are several system variables with further information:

 

Note

There are no Java-style exception objects.

 
 
 

Example

procedure toDate(aText)
argument VARCHAR aText;
{
  VARCHAR saveFmt := $datefmt;
  date    myDate  := $null;
  errorctl 1; // ignore following errors
  $datefmt = "MM/DD/YYYY";  myDate := aText;
  $datefmt = "MM/DD/YY";    myDate := aText;
  $datefmt = "D. MM. YYYY"; myDate := aText;
  $datefmt = "D. MMM YYYY"; myDate := aText;
  errorctl 0; // resume default failure mode
  $datefmt := saveFmt;
  print myDate, aText;
}
end procedure toDate;
toDate( "25.7.1966" );
toDate( "7/25/66" );
toDate( "25. July 66" );

Screen output:


07/25/1966 25.7.1966
07/25/1966 7/25/66
07/25/1966 25. July 66

 
 
 

Hint

In the Primebase Enterprise Objects (PBEO) framework you find the functions PBE:try() and PBE:catch()

They implement a nesting counter for the internally used errorctl function, maintain and evaluate the $sqlcode system variable.
 




 
 

12. Classes

The major new addition of PrimeBaseTalk to the previous DAL language is the introduction of object oriented programming. This is achieved by direct language support for the creation of indepenent modules, with their own variables and methods. Similar to other languages, especially C++ and Java, these modules are called classes.

A class is just another entity residing in the global namespace. It is introduced with the "class" keyword and its given name before the class declaration block which usually contains details of the class.
 
 

 

Example

class AB {
// a very simple class
};




 
 

Forward Declarations

Forward declarations allow references to not yet declared classes - for example two classes referring to each other. Of course, you should later provide the actual implementation.

Forward declarations may contain the extends clause, specifying a base class.
 
 

 

Example

class ABC extends AB;
ABC myVal;




 
 

Class Access

Classes are always public. The access keywords (public, protected, private) are not applicable, as class declaration already takes place at the global namespace.

Access of class members is described in the following section.




 
 

Inheritance

Classes can base their implementation on already declared classes. For object oriented programming this mechanism is called "inheritance". PrimeBaseTalk does not support "multiple inheritance".

To inherit all public or protected properties of a class into the currently declared new class, this base class has to get mentioned in the class declaration with the optional 'extends' keyword.
 
 

 

Example

class ABC extends AB {
};
All classes without explicit 'extends' automatically extend the class Object which is provided by the system.




 
 

Final Classes

Classes declared with the "final" keyword are not available for inheritance by another class. This is a very strong measure of protection, you should consider to instead explicitly make the existing methods final.




 
 

Abstract Classes

Classes declared with the "abstract" keyword can not get instantiated by themselves, but only through an inherited class.

Abstract classes don’t only allow, but require at least one abstract member function or procedure.
 
 

 

Example

abstract class AC1 {
        public abstract procedure a() end procedure a;
        public abstract void b();
};
abstract class AC2 {
        /* later */
}; /* illegal */




 
 

Class Redeclaration

It is possible to redeclare an existing class with the same name at any time. This is especially useful in development of interactive systems using the PrimeBase Application Server.

Existing objects survive though - they keep the association with the old class declaration. Preexisting compiled code, with parameter types of procedures and methods, also refers to the old class until recompiled. It won’t follow to redeclared classes.
 
 

 

Note

Although it is possible to supersede a class declaration by redeclaring the class, it is especially not recommended for the system classes.




 
 

Class Members

A member is an entity contained within a class. There are storage members - variables, and executable members - procedures and functions, also commonly called methods.




 
 

Access Operators

The colon ":" is used for any access of class or object members. The operators "." and "->" which are used by other languages for similar purpose have a slightly different meaning:

The "." operator is used to separate table aliases in database expressions from the columns identifiers.

The "->" operator is used for cursor columns.

The "::" operator is unused.




 
 

Static Members

Members declared with the keyword 'static' exist within the class rather than within single instances of that class - the objects.

They are accessible from within objects similarily to non-static members, but variables share the data across all instances.

In the following sample, everything refers to one shared variable "x".
 
 

 

Example

class A {
 static INT x := 1;
 static void PrintX() { print x; }
};
A aObj = new A();
print A:x, aObj:x;
A:PrintX();
aObj:PrintX();

Screen output:


1 1
1
1




 
 

Member Access

Access to the various members of a class is controlled using the modifiers 'private', 'protected' and 'public'.




 
 

13. Objects

Objects are independent instantiations of declared classes. There can be many different instances of the same class, or none.

Each object has its own set of member variables, as declared in the class. Since methods can't get changed, they are efficiently shared between all objects of that class.




 
 

Constructor

To create an instance of the class, the object has to be constructed by the appropriate method.

Similar to other languages, this method has the same name as the class itself. For easier referral, all these creation methods are called "constructor".

The constructor as used to create an object is invoked by a special syntax - the 'new' operator.

In comparison to other object oriented languages the whole object creation process is much simplified to gain maximum speed.

 

Example

class A {
 A() { print "A"; }
};
class B extends A {
 B() { print "B"; }
};
B bb = new B();

Screen output:


B
The order of these calls is not enforced by the language. You may even call to ancestor classes or call parent constructors multiple times.

The call to the parent constructor is super:this() not, super()
 
 

 

Example

class C extends B {
        C()
        {
                print   "C";
                super:this();
                super:super:this();
        }
        C(INT a)
        {
                print   "INT";
                this();
                super:this();
        }
};
C cc := new C();

Screen output:


C
B
A
To call the constructor without explicitly using the created object, you have to prefix the operator new with a colon.
 
 
 

Example

:new C(1);

Screen output:


INT
C
B
A
B

Inherited constructors are still available, even for derived classes.
 
 

 

Example

class A {
 A(INT x) { print x; }
};
class B extends A {
 B() {}
};
:new B(10);

Screen output:


10




 
 

Member Variable Initialization

During class compilation, non-static member variables are also available as static variables. Both kinds of member variables can get initialized during their declaration, or in a later static code block.

These assignments are evaluated only once, on class declaration. On class instantiation into an object, the values are duplicated. This is roughly equivalent to assigning a value to the prototype of a JavaScript class.
 
 

 

Note

If you assign references to non-static member variables, you share the referenced objects between instances of the class. To prevent this you should only preset to $NULL and initialize the members only during the constructor.

 
 
 
 
 

Example

class Testing {
        public /* non-static */ INT x := 1;

        static {
                // the prototype / template gets modified
                x := 2;
        }
};
/* would be a bug:
Testing:x = 3;
 */
print new Testing().x;

Screen output:


2
From now on, the prototype values are not accessible from outside.




 
 

Final Member Variables

Member variables declared with the keyword 'final' are write once - they may even get dynamically initialized from a function result.




 
 

finalize() as Destructor

The finalize() callback function supports additional cleanup task when an object is reclaimed by the garbage collecting mechanism: When all references to an object are lost (reference counting) or when found unaccessible during an explicit garbage collection, an object will get purged.

Similarily to Java, there is no destructor walking through the inheritance tree. Instead the special member function "finalize()" is called. An inherited super:finalize() requires an explicit call.
 
 

 

Note

Instead of throwing an exception as in Java, the garbage collection can get interrupted by introducing a new reachable reference to the object, during the call to finalize().
If the same object is again found by the garbage collection, it receives another finalize(), and so on.

For cycles (multiple objects connected between themselves, but from nowhere else) this may lead to a situation where some objects already got finalized before one new reference is established, breaking the whole step. There is no further notice to these other objects.




 
 

clone()

The clone() member function creates a duplicate of the object. The default implementation just copies the object itself, contained references will point to the same objects. A deep copy must be performed manually.




 
 

getClass()

The getClass() function yields an object representing the class. The only information currently available from class objects is the class name, via the GetName() method.




 
 

Member Procedures and Functions

Procedures declared within a class work the same way as global procedures. In addition you may change the access using the several keywords described for class members.

The separation of parameter list and parameter declaration resembles the abandoned old style of the original K&R C language.

Within class declarations, an alternate modern syntax becomes available for some methods.
 
 

 

Example

class MyClass {
 public static
 void anotherTest(INT x)
 {
        print   x;
 }
};




 
 

Static methods

Methods declared with the 'static' modifier are accessible with and without an instance of the class. They can only access static member variables, though.
 
 
 

Example

MyClass obj := new MyClass();
obj:anotherTest(1);
MyClass:anotherTest(1);

Screen output:


1
1




 
 

Abstract methods

Methods declared with the 'abstract' modifier are only a placeholder within an abstract class, without underlying code. The abstract class can not get instantiated into concrete objects (without inheritance) and has to be declared abstract itself.
 
 
 

Note

An abstract class requires at least one abstract method.
Abstract methods are declared without the statement block. Functions require an additional ";". Procedures still require the END PROCEDURE section.
 
 
 

Example

abstract class AClass {
abstract procedure myProc()
end procedure myProc;
abstract void myFunc();
};




 
 

Overloading

Inside one class multiple function methods may have the same identifier - they are overloaded. The functions must differ in at least one parameter type, though. The several integral types are considered to be the same - there can only be one of them. The same applies also to the different floating point types.
 
 
 

Example

class Over {
static void load(INT a)         { print "INT"; }
static void load(double a)      { print "FLOAT"; }
static void load(VARCHAR a)     { print "VARCHAR"; }
static void load(UNICODE a)     { print "UNICODE"; }
static void load(CHAR a)        { print "CHAR"; }
static void load(MONEY a)       { print "MONEY"; }
static void load(DECIMAL a)     { print "DECIMAL"; }
static void load(BINARY a)      { print "BINARY"; }
static void load(VARBIN a)      { print "VARBIN"; }
static void load(LONGBIN a)     { print "LONGBIN"; }
};
over:load(1);
over:load(SMINT 2);
over:load(INT 0x12345678);
over:load(DOUBLE 1);
over:load(FLOAT 1);
over:load(MONEY 1);
over:load(DECIMAL 1);
over:load("");
over:load(CHAR "");
over:load(VARBIN "");
over:load(BINARY "");
over:load(LONGBIN "");
over:load(UNICODE "");

Screen output:


INT
INT
INT
FLOAT
FLOAT
MONEY
DECIMAL
VARCHAR
CHAR
VARBIN
BINARY
LONGBIN
UNICODE
Overloading similarily works for non-static functions.

Overloading is only allowed for methods with the new function syntax. An attempt to overload a procedure would currently just replace it, later versions of PrimeBaseTalk will yield an error message.

It is not possible to have both static and non-static methods with otherwise similar name and parameters.




 
 

Overriding

Overriding is related to inheritance: A class extends another class and therefor inherits methods from that class. When a method in the new class is declared with the same identifier and parameters as a method in the base class, it is said to override that method.

When an overriden method is invoked on some object reference to the base class, the overriding code gets executed instead.
 
 

 

Example

class Base {
void test() { print "test"; }
};

class OverRide extends Base {
void test() { print "over!"; }
};
Base obj = new OverRide();
obj:test();

Screen output:


over!
Overridden functions won't hide other functions with the same identifier, as inherited from base classes. You need not redeclare and call the inherited functions.
 
 
 

Example

class OverRide extends Over {
static void load(VARCHAR a) { print "ride"; }
};
override:load(DECIMAL 1);
override:load("");

Screen output:


DECIMAL
ride




 
 

Final Methods

Instead of requiring a keyword (C++: virtual) for overridable methods, all methods are overridable by default.

Only methods declared with the 'final' modifier are not available for further overriding in inherited classes. This approach is similar to Java.
 
 

 

Example

class A {
final void ah() { print "ah"; }
};
class B extends A {
void ah() { print "boo"; }
};
B bb = new B();
bb:ah();

Screen output:


Symbol 'ah' is final.
Execution Failed.




 
 

Method Access

The access modifiers for class members have been discussed in the class section.

Method access rights are checked dynamically. Therefor even if you call a public method, a derived class may have overridden that method to more privacy.
 
 

 

Example

class A // implicitly extends Object
{
 private void clone() {}
}
A aa = new A();
Object o = aa;
o = o:clone(); // will fail




 
 

Reflection

Reflection is the self-description of classes and