0% found this document useful (0 votes)
2K views

Omnis Programming

Omnis Programming

Uploaded by

rojomuri
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2K views

Omnis Programming

Omnis Programming

Uploaded by

rojomuri
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 483

Omnis Programming

TigerLogic Corporation
June 2013
20-062013-02

The software this document describes is furnished under a license agreement. The software may be
used or copied only in accordance with the terms of the agreement. Names of persons, corporations, or
products used in the tutorials and examples of this manual are fictitious. No part of this publication may
be reproduced, transmitted, stored in a retrieval system or translated into any language in any form by
any means without the written permission of TigerLogic.
TigerLogic Corporation, and its licensors 2013. All rights reserved.
Portions Copyright Microsoft Corporation.
Regular expressions Copyright (c) 1986,1993,1995 University of Toronto.
1999-2013 The Apache Software Foundation. All rights reserved.
This product includes software developed by the Apache Software Foundation
(http://www.apache.org/).
OMNIS and Omnis Studio are registered trademarks of TigerLogic Corporation.
Microsoft, MS, MS-DOS, Visual Basic, Windows, Windows 95, Win32, Win32s are registered
trademarks, and Windows NT, Visual C++ are trademarks of Microsoft Corporation in the US and other
countries.
SAP, R/3, mySAP, mySAP.com, xApps, xApp, and other SAP products and services mentioned herein
as well as their respective logos are trademarks or registered trademarks of SAP AG in Germany and
in several other countries all over the world.
IBM, DB2, and INFORMIX are registered trademarks of International Business Machines Corporation.
ICU is Copyright 1995-2003 International Business Machines Corporation and others.
UNIX is a registered trademark in the US and other countries exclusively licensed by X/Open Company
Ltd.
Sun, Sun Microsystems, the Sun Logo, Solaris, Java, and Catalyst are trademarks or registered
trademarks of Sun Microsystems Inc.
J2SE is Copyright (c) 2003 Sun Microsystems Inc under a licence agreement to be found at:
http://java.sun.com/j2se/1.4.2/docs/relnotes/license.html
MySQL is a registered trademark of MySQL AB in the United States, the European Union and other
countries (www.mysql.com).
ORACLE is a registered trademark and SQL*NET is a trademark of Oracle Corporation.
SYBASE, Net-Library, Open Client, DB-Library and CT-Library are registered trademarks of Sybase
Inc.
Acrobat is a trademark of Adobe Systems, Inc.
Apple, the Apple logo, AppleTalk, and Macintosh are registered trademarks and MacOS, Power
Macintosh and PowerPC are trademarks of Apple Computer, Inc.
HP-UX is a trademark of Hewlett Packard.
OSF/Motif is a trademark of the Open Software Foundation.
CodeWarrior is a trademark of Metrowerks, Inc.
This software is based in part on ChartDirector, copyright Advanced Software Engineering
(www.advsofteng.com).
This software is based in part on the work of the Independent JPEG Group.
This software is based in part of the work of the FreeType Team.
Other products mentioned are trademarks or registered trademarks of their corporations.

Table of Contents

Table of Contents
ABOUT THIS MANUAL.....................................................7
CHAPTER 1THE OMNIS ENVIRONMENT ...............8
STUDIO BROWSER ...................................................................9
OMNIS PREFERENCES ............................................................11
STUDIO TOOLBARS AND MENUS ............................................12
CONTEXT MENUS ..................................................................17
FIND AND REPLACE ...............................................................19
COMPONENT STORE ..............................................................20
PROPERTY MANAGER ............................................................21
NOTATION INSPECTOR ...........................................................24
CATALOG...............................................................................27
SQL BROWSER ......................................................................28
SQL QUERY BUILDER ...........................................................31
VERSION CONTROL SYSTEM ..................................................40
OMNIS HELP ..........................................................................41
CHAPTER 2LIBRARIES AND CLASSES ..................43
OMNIS LIBRARIES ..................................................................43
DEFAULT CLASSES ................................................................46
CLASS TYPES.........................................................................48
CLASS TEMPLATES AND WIZARDS.........................................49
DATA CLASSES AND WIZARDS ..............................................50
OMNIS DATA TYPES ..............................................................51
SCHEMA CLASSES ..................................................................61
QUERY CLASSES....................................................................62
TABLE CLASSES ....................................................................62
CHAPTER 3OMNIS PROGRAMMING .....................64
VARIABLES ............................................................................65
METHODS ..............................................................................71
EVENTS .................................................................................93
USING TASKS.......................................................................104
EXTERNAL COMPONENT NOTATION ....................................113
CHAPTER 4DEBUGGING METHODS ....................117
INSERTING AND EDITING METHODS .....................................118
DEBUGGING METHODS ........................................................119

Table of Contents
INSPECTING VARIABLE VALUES ..........................................123
WATCHING VARIABLE VALUES ...........................................124
BREAKPOINTS ......................................................................125
THE METHOD STACK...........................................................127
DEBUGGER OPTIONS ...........................................................128
DEBUGGER COMMANDS ......................................................129
CHECKING METHODS ..........................................................130
METHOD PERFORMANCE .....................................................134
SEQUENCE LOGGING ...........................................................135
CHAPTER 5OBJECT ORIENTED PROGRAMMING136
INHERITANCE ......................................................................136
CUSTOM PROPERTIES AND METHODS ..................................143
OBJECT CLASSES .................................................................147
OBJECT REFERENCES ..........................................................152
EXTERNAL OBJECTS ............................................................154
INTERFACE MANAGER .........................................................156
CHAPTER 6LIST PROGRAMMING .......................158
DECLARING LIST OR ROW VARIABLES.................................159
DEFINING LIST OR ROW VARIABLES ....................................160
BUILDING LIST VARIABLES..................................................163
LIST AND ROW FUNCTIONS ..................................................164
ACCESSING LIST COLUMNS AND ROWS ...............................165
LIST VARIABLE NOTATION ..................................................165
MANIPULATING LISTS ..........................................................171
SMART LISTS .......................................................................174
CHAPTER 7SQL PROGRAMMING.........................181
OVERVIEW...........................................................................182
SETTING UP A DATABASE CONNECTION...............................182
CONNECTING TO YOUR DATABASE ......................................183
INTERACTING WITH YOUR SERVER ......................................185
LISTING DATABASE OBJECTS ..............................................199
REMOTE PROCEDURES ........................................................202
TRANSACTIONS ...................................................................205
CURSOR RESULTS SETS .......................................................208
STRIPPING SPACES ...............................................................213
TREATMENT OF DATE VALUES ............................................213
LARGE OBJECTS ..................................................................214
SESSION POOLS ...................................................................215
DIAGNOSING PROBLEMS ......................................................218
SESSION AND STATEMENT PROPERTIES AND METHODS .......219
SQL MULTI-TASKING AND SQL WORKERS .........................227
4

Table of Contents
CHAPTER 8SQL CLASSES AND NOTATION .......236
SCHEMA CLASSES ...............................................................236
QUERY CLASSES..................................................................238
CREATING SERVER TABLES FROM SCHEMA OR QUERY CLASSES 241
TABLE CLASSES ..................................................................242
TABLE INSTANCES ...............................................................242
SQL CLASSES AND SESSIONS ..............................................254
CHAPTER 9SERVER-SPECIFIC PROGRAMMING257
ORACLE ...............................................................................258
SYBASE ...............................................................................277
DB2 ....................................................................................290
MYSQL...............................................................................295
POSTGRESQL ......................................................................305
SQLITE ................................................................................319
ODBC .................................................................................327
JDBC ..................................................................................341
AMAZON SIMPLEDB DAM..................................................346
CHAPTER 10REPORT PROGRAMMING ..............361
REPORT FIELDS AND SECTIONS............................................361
REPORT WIZARD .................................................................362
REPORT TOOLS ....................................................................362
REPORT SECTIONS ...............................................................363
SECTION POSITIONING .........................................................366
SORTING AND SUBTOTALING ...............................................369
PRINTING REPORTS ..............................................................371
REPORT AND FIELD METHODS .............................................375
PRINT DEVICES AND THE CURRENT DEVICE ........................377
GLOBAL PRINTING PREFERENCES ........................................380
REPORT INSTANCES .............................................................383
REPORT FIELD AND SECTION METHODS ..............................386
REPORT OBJECT POSITIONING .............................................387
REPORT INHERITANCE .........................................................392
REPORT FONTS ....................................................................393
REPORT TEXT LABELS .........................................................394
PORT PROFILES....................................................................395
LABELS................................................................................397
HTML REPORT DEVICE ......................................................398
CHAPTER 11UNICODE .............................................402
WHAT IS UNICODE? .............................................................402
OMNIS DATA FILE CONVERSION ..........................................403
DAMS .................................................................................404
5

Table of Contents
CHARACTER NORMALIZATION .............................................409
CHARACTER TRANSLATION .................................................412
UNICODE CLIENTS ...............................................................412
UNICODE DATA HANDLING .................................................413
IMPORT/EXPORT AND REPORT FILE ENCODING ...................415
CHAPTER 12LOCALIZATION.................................417
LOCALIZING YOUR LIBRARIES .............................................417
LOCALIZING OMNIS .............................................................428
LOCALIZING THE OMNIS RUNTIME.......................................430
CHAPTER 13VERSION CONTROL.........................435
OVERVIEW...........................................................................436
SETTING UP A PROJECT ........................................................437
CHECKING IN COMPONENTS ................................................441
USING THE VCS ..................................................................446
MANAGING COMPONENTS ...................................................458
VCS OPTIONS......................................................................464
REPORTS .............................................................................467
INDEX ...............................................................................468

Studio Browser

About This Manual


This manual focuses on the programming and higher level aspects of developing
applications in Omnis Studio, and includes information about creating and using List
Variables, accessing and managing SQL databases, as well as describing various
development tools in Omnis such as the VCS.
If you are new to Omnis Studio you should read the Introducing Omnis Studio manual to
learn how to create libraries and add classes and components to your Omnis library. To find
out how to create web and mobile apps you should read the Creating Web & Mobile Apps
manual.
In addition to these manuals, there are the Omnis Reference manuals, and a comprehensive
Help system describing the Omnis Studio commands, functions, and the notation, available
from within the Omnis Studio development environment using the F1 key.

Chapter 1The Omnis Environment

Chapter 1The Omnis


Environment
The tutorial introduced you to some parts of the Omnis IDE and you will have used the
common tools in Omnis, such as the Studio Browser and the Catalog. This chapter goes into
more detail about these tools and others in the Omnis Studio SDK. Some of the tools and
development features in Omnis, such as the Omnis VCS and using the SQL Browser, are
explained in greater detail in their own respective chapters later in this manual.
The Omnis development environment contains all the tools you need to build enterprise,
web, and mobile applications in a cross-platform, multi-developer environment. When you
first launch Omnis Studio the Welcome window or start page is opened.

Omnis Studio shown here on Windows 7, but it looks virtually the same on OS X or Linux.

Studio Browser
This contains useful information about the product and sample web apps, and it provides
access to the online Tutorial. When you close the Welcome window, you will see the Studio
Browser.
Note: Some editions of Omnis Studio may not provide access to all the development tools
or web/mobile development features, such as the Omnis VCS or the DAMs in the SQL
Browser.

Studio Browser
The Studio Browser is the main window in Omnis Studio for developing your applications
and managing server database sessions. The hierarchical folder list down the left side
contains a list of all open Libraries, Omnis Data Files, SQL database sessions, and provides
access to the Omnis Version Control System (VCS); the SQL Browser and VCS are not
available in some editions of Omnis Studio. The toolbar at the top of the Studio Browser
window lets you navigate around the Omnis environment and change its view options. For
example, the Folders button option lets you hide and show the hierarchical folder list. You
can right-click on the Browser to change its view options (Large or Small icons, or Details
view), and the Save Window Setup option lets you save the current settings.

The Studio Browser showing the contents of a library in Large Icons view.

The right hand pane displays a list of objects or files for the current folder, e.g. it displays
all the classes in a library when a library is selected in the Folders list on the left. The list of
Options (they look like hyperlinks) will change depending on the object currently selected

Chapter 1The Omnis Environment


in the Folders list or the file browser on the right and will always provide options and
shortcuts to perform actions on the current object.

Library Folders
The Studio Browser lets you create folders in a library so you can organize the classes
within each library. Folders are in fact Omnis classes, but for display only (they are visible
during development only). Folders do not perform any function in your library, other than
organizing your classes, and they are ignored at runtime.
To hide/show library folders within the Browser, select your library and click on the
Library folders option, or alternatively, right-click on the white space of the Browser
(when any library is selected) and select the Library Folders option from the context
menu. You can save the state of this option using the Save Window Setup option for the
Browser.

Hiding and Showing Classes


You can hide and show different types of class in the Studio Browser by pressing the Shift
and Control/Command keys plus the appropriate letter key. For example, pressing
Shift+Ctrl+W causes only windows to be displayed, or Shift-Ctrl/Cmnd-A shows all classes.
The following keyboard shortcuts are available:
Shift +
Ctrl/Cmnd +
A
W
F
R
L
M
O

Displays...
all classes
windows only
files only
reports only
searches only
menus only
object classes only

Shift +
Ctrl/Cmnd +
J
C
T
S
U
B
Y

Displays...
tasks only
code classes only
toolbars only
schemas only
query classes only
tables only
system tables only

The Class Filter allows you to specify which types of class are shown in the Studio Browser
or not. To open the Class Filter, press the F7 key or click on the Class Filter (on/off) option
in the Studio Browser.

Recent Classes
Any classes that you have opened recently are listed in the Recent Classes popup list
displayed at the bottom of the Studio Browser. To open a class, you click on the list and
select the class name. The class will be displayed in the appropriate class editor.

10

Omnis Preferences
You can open the method editor or Interface Manager for a class (that is, a class that can
contain methods) from the Recent Classes list in the Studio Browser. To open the method
editor for a class, click on the Recent Classes list and hold down the Shift key and select the
class, or to open the Interface Manager for a class, hold down the Control/Command key
while selecting the class in the Recent classes list.

Omnis Preferences
The Omnis preferences or Options control the overall behavior of Omnis itself, rather than
individual libraries, and include groups of preferences for: General options, Appearance,
Devices, Methods, and Page Setup. You can change the Omnis preferences in the Property
Manager. The Omnis preferences are sometimes referred to as the Omnis Root
Preferences, since they are properties of the Omnis Root object (in the notation they are
referred to using $root.$prefs.<property-name>).
To view the Omnis preferences

Select the Options/Preferences menu option in the Tools menu or toolbar

or

Click on Studio in the Studio Browser and click on the Prefs option

Edit the Omnis preferences in the Property Manager

The Omnis Preferences are displayed in the


Property Manager. You can position your mouse
over any property in the Property Manager and
view its description in a tooltip.

Or you can select a preference (property) in the


Property Manager and press F1 to open a Help
window for that preference.

11

Chapter 1The Omnis Environment

Environment Font Size


The Omnis preference $idelistpointsize specifies the font point size used for lists within the
main IDE windows in Omnis, including the Studio Browser, Catalog, and Property
Manager. If you change this property, the new value is used when you restart Omnis.

Studio Toolbars and Menus


The main toolbar at the top of the Omnis application window provides access to all the
development tools in Omnis, such as the Studio Browser, the Catalog, the Property
Manager, and so on. The Standard, View, and Tools toolbars contain many of the same
options as the File, View, and Tools menus respectively. The Desktop toolbar (hidden by
default) lets you switch between design and runtime environments.
You can drag any of them out of the docking area and place them anywhere (floating) in the
Omnis application window. You can place your mouse over any button to display its name
or tooltip description.
To hide or show any of the toolbars, or install the main Omnis menu bar, you can Rightclick/Ctrl-click in the toolbar area of the main Omnis development window and select the
Toolbars or Menu Bar option. See the Omnis Menu Bar section.

Standard toolbar
The Standard toolbar has more-or-less the same options as the File menu. In addition, the
File menu lets you create new libraries and open existing libraries.
The Save option (Ctrl/Cmnd-S) saves the class you are currently working on. If a class
design window is not currently selected this option is grayed out.
The Revert option rolls back any changes you have made to the class you are currently
working on. Note that if you close an Omnis class it will be saved automatically and
therefore cannot be reverted.
The Dest option opens the Print Destination (Shift-Ctrl/Cmnd-P) dialog which lets
you set the destination of the current output. Reports are sent to the Screen by default,
but you can choose another destination from this dialog.
The Print option (Ctrl/Cmnd-P) prints the current class or report to current destination,
if applicable. For example, when you are working in the method editor the option prints
the currently selected method or set of class methods.

12

Studio Toolbars and Menus

View toolbar
The View toolbar opens the main Studio Browser and other tools available in the Studio
development environment, and has the same options as the View menu. Many of these tools
are described in greater detail later in this chapter.
The Browser option (F2/Cmnd-2) opens the Studio Browser which lets you create and
examine libraries and classes. If the Studio Browser is already open and in Single
Window Mode this option will bring it to the top. If the Browser allows multiple copies
of itself, this option opens the initial Browser displaying the libraries.
The CStore option (F3/Cmnd-3) opens the Component Store which contains data and
GUI objects, as well as external components, to allow you to build windows, web
forms, and reports. This option will be grayed out if there is no design window or
report on top. (Note you create classes from the Studio Browser itself, so this option
will be grayed out when a library is selected in the main Studio Browser.)
The Notation option (F4/Cmnd-4) opens the Notation Inspector which lets you view
the complete Omnis notation tree. If the Notation Inspector is already open and in
Single Window Mode this option will bring it to the top. If the Notation Inspector
allows multiple copies of itself, this option opens a new instance of the Notation
Inspector. When you open the Notation Inspector the Property Manager will also open.
The Props option (F6/Cmnd-6) opens the Property Manager which lets you view or
change the properties of an object; the properties displayed in the Property Manager
will depend on the object or window currently selected or on top in the Omnis
development environment. If the Property Manager is already open, this option will
bring it to the top.
The Catalog option (F9/Cmnd-9) opens the Catalog which lists all the field names and
variables in your library, together with the functions, constants and event messages. If
the Catalog is already open this option will bring it to the top.
In addition, the View menu contains the Inheritance option:
The Inheritance Tree option (F5/Cmnd-5) lets you view the inheritance or
superclass/subclass hierarchy in the current library. If you select a class in the Browser
and open the Inheritance Tree it shows the inheritance for that class.

13

Chapter 1The Omnis Environment

Tools toolbar

The Tools toolbar lets you edit the global Omnis preferences, open the Trace log, the
Omnis Icon Editor, Export & Import data, open the Ad hoc report tool, and so on.
The Trace Log option displays the trace log which is a record of the operations and
commands you have carried out. See the Debugging Methods chapter in the Omnis
Programming manual for further details.
The New Users option lets you open the New Users section of the Welcome
application: in particular you can view many sample Omnis libraries from New Users,
as well as view the tutorial.
The Add-Ons option lets you open various additional tools, including:
Character Map Editor, for mapping local and server character data
Compare Classes tool, for comparing the methods in classes and libraries
Method Checker, for checking methods in classes and libraries
ODBC Admin tool, for setting up ODBC access to Omnis datafiles
Port Profile editor, for setting up your ports
String Table Editor, for providing multi-languages in your application
Web Client Tools, for configuring your Omnis web and mobile apps

14

Studio Toolbars and Menus

Desktop toolbar
The Desktop toolbar (hidden by default) lets you toggle between the design environment
and a simulated Runtime environment so you can see your application in user mode. You
can also change the mode using the Desktop option in the File menu.
In Design mode the standard menus, such as File, Edit, View, and Tools toolbars are
visible. In Runtime mode all these are hidden and only user menus, data entry windows and
toolbars defined in your library are visible. Also in runtime mode there is a cut-down
version of the File and Edit menus on the main menu bar. Being able to switch to Runtime
mode lets you see exactly how your application will look when the user runs it. In
Combined mode (the default) all design and user menus, windows, dialogs, and toolbars are
visible. When you select the Runtime option, the Desktop toolbar is installed so you can get
back to the Combined mode.

Omnis Menu Bar


The main Omnis Menu Bar gives you access to various File operations, the standard Edit
menu functions, as well as the View, Window, Tools, and Help menus. Many of the options
in these menus appear on the main toolbars and are described in the previous sections; the
other options are reasonably self-explanatory.

Under Windows Vista, the main Omnis menu bar may not be visible, but you can press the
Alt key to display it temporarily. To display it permanently, do the following:
Right-click/Ctrl-click on the main Omnis toolbar and
select the Menu Bar option to show it permanently on
the main Studio window.
The other options on the Toolbar context menu let you
configure the main toolbars in Omnis Studio. The
Toolbar Options option let you install or remove the
Standard, View, Tools and Desktop toolbars

15

Chapter 1The Omnis Environment

Tools menu
The New Users option lets you open the New
Users section of the Welcome application: in
particular you can view many sample Omnis
libraries from New Users, as well as view the
tutorial.
The Help Project Manager lets you build help
into your own libraries for the benefit of your own
users; it is described in the Omnis Programming
manual.
The Add-Ons option lets you open various
additional tools (described in the Tools toolbar
section)
The Export Data option lets you export data from
an Omnis data file (not a SQL database) using a
number of different data formats. While the
Import Data option lets you import data into a data file from an existing export file or
text file from
another application. For further details about importing
and exporting data see the
Omnis Programming manual.
The Icon Editor option opens the Icon Editor which lets you add your own icons to
Omnis. It is described in the Library Tools chapter in the Omnis Programming manual.
The Trace Log option displays the trace log which is a record of the operations and
commands you have carried out. See the Debugging Methods chapter in the Omnis
Programming manual for further details.
The Options option opens the Property Manager displaying the main Omnis
Preferences, including settings for the Appearance of the Omnis environment, the Print
devices for Omnis reports, the main Page Setup, and Java.
The Change Serial Number option which lets you re-serialize your copy of Omnis,
and add serial numbers for Omnis plug-ins.

16

Context Menus

Context Menus
A context menu is a useful shortcut when you want to modify an object, or change the
Omnis development environment. You can open context menus from almost anywhere in
Omnis by Right-clicking on the object or browser window. On OS X, you can open a
context menu by holding down the Ctrl key and clicking your mouse on the object. The
options in a context menu depend on the object you click on. For example, if you Rightclick on the Studio Browser its View menu will be opened containing options for changing
its view and creating new classes. Note the Save Window Setup which will save the current
setup or view; this useful option is available for many of the Omnis development windows.

The context menu on the Studio Browser lets you change the current view, or create a new class or
folder when a library is visible in the Browser.

17

Chapter 1The Omnis Environment

Variable Context menus


In the Omnis Method Editor or Catalog, you can right-click on a variable name and get its
current value. The Variable context menu shows the variable name, its value and its type
and allows you to open the variable window showing its current value.

You can right-click in many parts of Omnis and open up a menu


appropriate to the object or item under the mouse, like a variable
displayed in the method editor, as above.

18

Find and Replace

Find and Replace


The Find & Replace tool lets you search through a class or library, or a number of classes or
libraries, to find a particular text string. You can selectively replace occurrences of an item
or replace all items.
The Find And Replace option under the Edit menu (or Ctrl/Cmnd-F) opens the Find &
Replace dialog; note the Find Next option (Ctrl/Cmnd-G) lets you find the next occurrence
of the current find string.

On the Classes tab you can select the libraries and classes in which you want to perform the
find and replace. For a single library you can select some or all of the classes in the library.
If you select more than one library under the Classes tab, all classes in all selected libraries
are searched.
If you click on the Find First button Omnis will jump to the first occurrence of the text
string in your selected classes or libraries. For example, if the specified item is found in a
method Omnis will open the class containing the method with the found item highlighted.
Find Next (Ctrl/Cmnd-G) will jump to the next occurrence of the text string, and so on. The
Find All button finds all occurrences of the specified item in all the classes or libraries you
selected and lists them in the Find log.
19

Chapter 1The Omnis Environment


Note the Omnis Find & Replace supports the standard notation for regular expressions, such
as described at http://en.wikipedia.org/wiki/Regular_expressions.
You can interrupt a find and replace operation at any time by pressing Ctrl-Break under
Windows, Ctrl-C under Linux, or Cmnd-period under OS X.

Renaming objects
When you rename certain objects in your library, Omnis will replace all references to the
object automatically. For example, if you rename a class variable in the method editor
Omnis will replace all references to the variable within the class automatically. However if
you try to rename most other types of object, such as renaming a class in the Browser,
Omnis will prompt you to find and replace references to the object. If you answer Yes to the
prompt, Omnis will open the Find & Replace tool and the Find log which lets you monitor
the find and replace, or control whether or not certain references are replaced.

Component Store
The Component Store contains the objects and components you need to build web and
mobile forms, reports and toolbars. When you create a new class or modify an existing one,
the Component Store will open automatically. For example, when you create or modify a
remote form in your web or mobile app, the Component Store will display the JavaScript
Components.

To create an object, you can drag the appropriate icon from the Component Store and drop
it onto your remote form, report or toolbar. Alternatively, you can select the button in the
Component Store and draw the object on your remote form or report as required.
You can change the view of the Component Store using the View context menu, by Rightclicking/Ctrl-clicking inside the Component Store and selecting the options you require. For
example, you can select the Text option to display the name of each component (as shown).
You may find this helps you identify each type of component while you become familiar

20

Property Manager
with Omnis. You can also resize the window to place it along the bottom or down the right
side of the Omnis development window.
When you have set up the Component Store how you want it, you can save the view options
using the Save Window Setup option in the context menu.

Property Manager
The Property Manager lets you display or change the properties of the currently selected
object. This could be a library, a window or the Omnis global preferences. The Property
Manager will normally appear automatically when needed; if it is not visible you can
display it either by selecting the View>>Property Manager menu item from the main menu
bar, by pressing F6/Cmnd-6, or by selecting the Properties option from an objects context
menu.
The properties of an object are shown in the
Property Manager in alphabetical order by
default, but you can list them functionally by
unchecking the Sort by Property Name
option in the Property Manager context
menu.
The other options in the Property Manager
context menu affect the behavior of the
Property Manager. If set, the Hold Updates
option stops the Property Manager updating
its contents automatically when you click on
another object. For example, you can click
on a window class to show its properties in
the Property Manager, select the Hold
Updates option, click on a field in the
window, and the Property Manager still
displays the properties of the window. Most
of the time however youll want this option
turned off so the Property Manager updates
itself automatically.

21

Chapter 1The Omnis Environment

Property Descriptions
The Help tips option in the Property Manager context menu displays short descriptive help
messages for each property in the Property Manager: this is particularly useful for showing
the parameters of a method. The Show Runtime Properties option lets you view properties
that are normally available in runtime only, that is, properties of an instance rather than a
design class. When runtime properties are visible in the Property Manager the methods for
the instance are also shown. You cannot set runtime properties or run methods from the
Property Manager itself, but you can drag references to them into your code in the method
editor (see below).

With the Help tips option enabled, the


Property Manager shows a short description
for each property.

When methods are visible in the Property Manager,


the help tips show a description and the parameters
for each method.

Note you drag a property or a method (and its parameters) from the Property Manager into
the Method Editor when you are writing code: see Dragging Methods below.

Copying Properties
The Copy Properties option lets you copy all the properties of one object and paste or
apply them to another object of the same type: this is useful if you want to reproduce or
duplicate a particular object, or even apply the properties of a built-in field to an external
component.
When you have set up the Property Manager how you want it, you can save the view
options using the Save Window Setup option in the context menu.

22

Property Manager

Show Property Context Menu


You can specify any built-in property to be displayed in the window or report field context
menu by Right-clicking on the property in the Property Manager (when a field is selected)
and selecting Show property using editor context menu. For example, the context menu for
window and remote form editors shows Show $order, which allows you to display field
ordering, but you can change it to most other properties. The field $ident is shown in the
report editor context menu. This does not work for properties specific to external
components, so for such properties the Show property... option is grayed out.
Save Window Setup in the Property Manager saves the selected property. A different
property can be saved for each class editor.
The property value is displayed for background objects. If a property is not supported by an
object, then nothing is displayed for that object.

Dragging methods from the Property Manager


Apart from displaying the properties and methods of classes and objects, the Property
Manager lets you transfer a property or method and its notational path to your Omnis code
in the method editor. You do this by dragging the property or method out of the Property
Manager and dropping it onto your code in the method editor, for example, you could drag
a method, such as the $senddata() remote form method, and drop it onto the calculation
field of the Do command.

When you drag a method out of the Property Manager and drop it onto your code, its full path and
parameters are copied as well. You can click in your code and edit the path and replace the parameters
with your own variable names.

23

Chapter 1The Omnis Environment

Notation Inspector
Omnis structures its objects in an object tree, or hierarchical arrangement of objects and
groups that contain other objects. The complete tree contains all the objects in Omnis itself,
together with your design libraries, classes, and other objects created at runtime. You can
view the complete object tree in the Notation Inspector.
To facilitate a system of naming or referring to an object in the object tree, and its
properties and methods, Omnis uses a system called the notation. The notation for an object
is really the path to the object within the object tree. The full notation for an object is shown
in the status bar of the Notation Inspector. You can use the notation to execute a method or
to change the properties of an object, and you can use a notation string anywhere you need
to reference a variable or field name.
The Notation Inspector therefore lets you view the Omnis object tree from the $root object
down. It is particularly useful for viewing the contents of your library and finding the right
notation for a particular object or group of objects in your library. For example, you can get
the notation for an object on a design or open window using the Notation Search tool on the
Notation Inspector toolbar. When you click on an object or group in the Notation Inspector
the Property Manager will display its properties and methods.

The Notation Inspector lets you drill down the hierarchy of objects within the Omnis tree; for example,
you can view the object tree for an open remote form in the $iremoteforms group; when you click on an

24

Notation Inspector
open remote form name, the Property Manager displays the runtime properties and methods of the
form.

When the Notation Inspector opens it shows the $root object which contains all the objects
in the Omnis object tree including all your open libraries and their contents. It also includes
all the objects and groups created at runtime when you run your application. You can
expand each branch of the tree to show the contents of an object or group.
All the different types of class in your library are shown in Notation Inspector within their
respective object group. For example, all the window classes in your library are contained in
the $windows group. Likewise all the toolbar classes are contained in the $toolbars group.
Note that the $classes group contains all the classes in your library. Also note that a group
may be empty if your library does not contain any classes of that type.

Finding the notation for an object


You can find the notation for a window object in design or runtime mode, also report
objects and toolbar objects. To do this, click on the Notation Search button on the Notation
Inspector toolbar then click on the object in your open window or toolbar. The Notation
Inspector will refresh itself showing the notation for the object you clicked on. The object
becomes the root of the tree, so you can expand the tree to view its contents.

You can click the Search button, then click on a button or other object on an open window and view its
notation in the Notation Inspector; the tree is redrawn and you can drill down to the view the contents of
the object.

Dragging notation from the Notation Inspector


Having found the object youre interested in, you can copy its full notation to the clipboard
and paste anywhere in your library, or you can drag an item from the Notation Inspector and
drop it onto your code in the method editor. For example, you can drag the item into the
calculation field of the Do command in the method editor.

25

Chapter 1The Omnis Environment

Notation Helper
The Notation Helper is built into the Method Editor and assists you in writing Omnis
notation. When you are typing a notation string into the calculation field of the method
editor you can pause to allow the Notation Helper to popup a list of possible properties,
methods, and variable names that can be used in the current notation string; the list is
context-sensitive, therefore as you type the first few characters of a property, method, or
variable name Omnis modifies the contents of the list accordingly. For example, if you type
Do $cinst.$sen the list pops up containing $sendall(), $senddata(), $setcurfield, and so on.
The list will display all methods and variables from the superclass of the current class if it is
a subclass.
When the list pops up you can use the up and down arrow keys, and then the Return key to
select the property, method, or variable you require, or you can use your mouse.

26

Catalog

Catalog
The Catalog lists all the variables, schema & query class columns, and string tables in your
library, in addition to listing all Omnis functions, constants, event codes, and hash variables.
The Catalog lists all the variables for the current object including task, class, instance, local,
and parameter variables, and also event parameters. For example, if you are working in a
window class the Catalog will show the class and instance variables for that window class.
In addition, when you select a particular method in the method editor, the Catalog will list
the local and parameter variables for that method.

The context menu on the Catalog lets you


change its appearance and style of tabs.

You can right-click on any variable or field name to


view its type, current value and other information.

Dragging items from the Catalog


When you have found an item in the Catalog, a variable, a schema class, an event, and so
on, you can enter its name into a calculation field by double-clicking on it (assuming the
cursor is in the calculation field) or by dragging it out of the Catalog and dropping the item
in the appropriate place into your code in the method editor.

27

Chapter 1The Omnis Environment

SQL Browser
The SQL Browser lets you access and interact with a number of remote server databases,
including Oracle, MySQL, PostgreSQL, OpenBase and SQLite. Omnis Studio provides a
separate Data Access Module (DAM), or Object DAM, to connect directly to each server
database. In addition, the SQL Browser contains a JDBC DAM and an ODBC DAM that
allow you to access JDBC- and ODBC-compliant databases, such as MS SQL Server, and
many others. The SQL Browser contains a session template for each database server
supported in Omnis.

The SQL Browser contains a session template for each supported server database including Oracle,
MySQL, PostgreSQL, OpenBase, and SQLite, as well as generic JDBC and ODBC connections. Note
that, in some cases, a session template may not be displayed if the appropriate clientware is not
installed on your computer.

The SQL Browser also contains an Omnis SQL DAM that lets you access an Omnis data
file using SQL methods rather than the Omnis Data Manipulation Language (DML).

Creating and Editing a Session


In the SQL Browser, you can create a new session, or duplicate an existing one and modify
it adding your own connection parameters. For most purposes, the quickest and easiest way
to create a new session is to duplicate an existing template and modify it.

28

SQL Browser
To create a new session to your database

Click on the SQL Browser option in the Studio Browser, then click on the Session
Manager option
Select the type of database you want to connect to and click the Duplicate Session
option
Rename the session using a suitable name for your database
Double-click the session template and modify the parameters in the Modify Session
dialog

When you create or modify a database session you need to select the DBMS vendor, the
Data Access Module (DAM) and version, as well as specifying the Username and Password
for the session. The connection parameters required will vary depending on your database.

Opening a session and accessing your data


Having defined or modified your session template, you can open or log onto your session in
the SQL Browser.

29

Chapter 1The Omnis Environment


To open a database session

Click on the SQL Browser option in the Studio Browser

Click on the Open Session option and then the session name

Double-click on the Tables object to view the tables on your database

Right-click on a table name and select the Show Data option

If you use the Show Data option on the SQLite database used in the tutorial, you can view the text and
images in the database.

Once you have created your database session you can view your data using the Interactive
SQL tool, as above, or create windows and forms based on the session using the SQL Form
Wizard in the Studio Browser.
Note that the Tutorial in this manual shows how you can build a SQL form to access data
via a web browser on a desktop PC or mobile device.

30

SQL Query Builder

SQL Query Builder


The SQL Query Builder (SQB) lets you build, run and store SQL Queries quickly and easily
using a graphical interface. The SQB is built into the Omnis Studio IDE and is easily
accessed via the SQL Browser. The SQB supports the generation of both simple queries
requiring little SQL knowledge and more advanced queries using different join types and
clauses. You can save queries for later use and you can create Omnis query classes based on
your queries to allow you to take advantage of the queries you build in the SQB in your
applications.

SQL Query Builder window


You can open the SQL Query Builder by clicking on the Query Builder option when the
SQL Browser option is selected in the main Studio Browser window. The SQB window has
three main panes: the table pane on the left showing all available tables, the main design
area at the top-right showing the query in graphical format, and the lower tab pane for
defining aliases, SQL clauses and expressions.

31

Chapter 1The Omnis Environment


All panes in the Omnis SQB are resizable and can be saved via Save Window Setup of the
main context menu. The list of available tables may also be refreshed at any time via the
table list context menu.

Creating a Query
The SQL Query Builder allows you to construct most types of query simply using drag and
drop and the context menus available as appropriate in each pane of the main SQB window.
In order to construct a query, you must be logged on to a SQL session via the SQL Browser.
The first time you open the SQB the query list will be empty allowing you to create a new
query. If an existing query is currently displayed pressing either the New toolbar button or
selecting <new query> from the query dropdown list will clear the query from the screen.

Selecting a SQL Session


All open sessions are shown in the droplist at the top-left of the SQB window. You can
select a session to build your query by dropping down the session list and selecting a
session.

Adding a Table
Once a SQL session has been selected a list of tables for the current session is shown in the
left hand pane. To include a table in a SQL Query simply drag the table into the main design
area on the right.

Removing a Table
You can remove a table from a query either by clicking on the X icon for the table or by
opening the context menu for the table and selecting Remove Table. You have to confirm
if you want to remove a table from the current query.

Refreshing a Table
If a table has been modified outside the SQB, you can refresh the table in the SQB by rightclicking on the table and selecting Refresh Table from the context menu. This option will
add any new columns or remove any deleted columns to reflect the current state of the
server table.

Selecting Columns
Once a table has been added, you can select columns by selecting their names individually
or by right-clicking on the table you can check or uncheck all the columns in the table.
Alternatively, you can specify that the SQB checks all columns automatically when a table
is added using the Select all Columns on drop option within the Options dialog (see the
Options section).

32

SQL Query Builder

Adding Column Aliases


You can add an alias for each selected column in the Columns tab of the lower tab pane by
clicking in the Alias column of the current line.

You can reorder columns in this pane by dragging and dropping column names in the list.

Creating Joins
To construct your queries, you can create joins between tables either using drag and drop in
the main SQB design area or using the Table Joins dialog. To create a join, drag a column
name from one table and drop it onto the column name within the table you wish to join
with. Alternatively, you can right-click on a table to open the Table Joins dialog from the
context menu.

33

Chapter 1The Omnis Environment


The Table Joins dialog lets you modify joins, set the operator and type, re-order using
drag and drop and switch columns using the context menu.
Joins may also be deleted via the context menu of the joined column in the main design area
and Line and style preferences can be set via the Options dialog.

Adding Column Expressions


In addition to specifying aliases, the Columns tab of the lower tab pane lets you add
expressions to a query via the context menu. Selecting Add Expression from the context
menu opens a dialog where you can add common SQL expressions such as AVG, COUNT,
MAX, MIN and SUM.

Adding a Where Clause


You can add a Where clause condition by dropping a column from a table onto the Where
Clause pane of the lower tab pane. When you drop a column the Where Clause dialog is
opened automatically and the column is pre-selected. You can also right-click on the Where
Clause pane to Edit the column conditions for the current query.

34

SQL Query Builder

Adding a Group by Clause


You can add a Group By clause, to group selected rows together to return a summary of
information, by dropping a column name onto the Group By pane of the lower tab pane.
You can also add a Having Clause to restrict the rows used by the Group By clause either
by dropping a column from a table or via the context menu.

Adding an Order by Clause


You can add an Order By clause by dropping columns onto the Order By tab of the lower
tab pane; when you drop a column Descending order is selected by default but you can
change it to Ascending. You can add Expressions to the Order By clause using the context
menu by right-clicking on the Order By pane.

Modifying the SELECT Construct


The Header Tab in the lower tab pane lets you enter an alternative construct, such as
SELECT DISTINCT and where supported SELECT TOP 100. This tab also lets you add
comments to precede the generated SQL Statement.

Adding Extra Query Text


The Footer Tab in the lower tab pane lets you add any additional query text to be
appended to the generated SQL Statement.

35

Chapter 1The Omnis Environment

Running a Query
You can run the current query from the main toolbar in the SQB window using the Build
and Run or Run option. Both buttons switch the main pane to the Results pane showing
the SQL script and results generated by the Query. You can make changes to the SQL script
generated if required and the query can be executed again using the Run button. Note that
using the Build and Run option will rebuild the statement from the saved query text and
therefore overwrite any changes you may have made.

Any errors which occur are reported in the status bar. If the full error text is not displayed,
you can click on the status bar to open a dialog showing the full error text.

Saving a Query
You can save a query using the Save or Save As toolbar option. When using Save
option for the first time, or the Save As option, you can add a description for the query.
The description is also available to view/edit via the Query Info option of the main context
menu. Once saved, a Query is added to the list of Queries available in the dropdown list in
the main SQB toolbar.

36

SQL Query Builder

Deleting a Query
The Delete button in the SQB toolbar button lets you delete the currently selected query
(you must confirm the deletion).

Query Reports
There are two types of report available via the Print button on the main toolbar or the
context menu opened by right-clicking on the Query design pane: both these options open
the Print Query dialog that allows you to print either the Structure or the Results of the
current query. In addition, you can include the generated SQL Script from the last executed
SQL query in both reports.

Query Structure Report


The Query Structure report shows the tables and their joins where the selected columns
are represented by an astrix *.

37

Chapter 1The Omnis Environment

Query Results Report


The Query Results report shows the results of the last executed SQL query. Column
widths reflect those of the results pane and may therefore be adjusted prior to printing.

Query Info
The Query Info dialog available from the main query context menu displays information
about the current query. You can change the name and description of query.

38

SQL Query Builder

Options
You can set various options for the SQL Query Builder in the Options dialog which is
available from the context menu on the main query window. You can specify the line and
color styles for joins, and you can set preferences for dragging and dropping during table
creation.

For databases where table names are prefixed by a username, the Omit Username option is
particularly useful when running the same query against different databases where the
username is different, but the table and column names are the same.

Creating a Query Class


You can create an Omnis Query class based on the current quer. To do this, you can drag
the current query from the main query design window on the right and drop it on to an open
library in the main Studio Browser. When you create a query class in this way, all the
additional query text is added to the class, together with any associated Omnis Schema
classes in order to map to the server tables in the query. Note that this feature is restricted
by the same limitations as a query class and therefore only supports Where Clause joins.

Creating a Statement Block


You can copy the generated SQL Script to the clipboard in a Begin Statement, Sta:, End
Statement block by right-clicking on the Results pane and selecting Create Statement
from the context menu. You can paste the statement into an Omnis method, providing an
alternative method of executing your query in an Omnis Studio library where a query class
is not appropriate.

39

Chapter 1The Omnis Environment

SQL Query Builder App


A runtime or end user version of the SQL Query Builder application is available on request.
Please contact your local Omnis sales or support office for details.

Version Control System


Note that some editions of Omnis Studio do not allow access to the Omnis VCS.
The Omnis Version Control System (VCS) lets you manage and revise Omnis libraries and
other application components systematically. In a team environment, with several people
working on the same application at the same time, you need to ensure that only one person
can change a particular component at a time.
Using the Omnis VCS you can control the development of your Omnis applications, or any
other project involving many different files such as Internet or Intranet applications.
Specifically, the VCS can manage Omnis libraries or their classes, external components,
DLLs or Code Fragments, Omnis data files, text or word processor files, Html and web
server files, or any other types of file required in your Omnis application.
The Omnis VCS has an easy-to-use environment that allows you to check-in and check-out
components, plus it had a useful tool that lets you compare different versions of the same
library or different revisions of the same component.
The Omnis VCS is described in detail in a later chapter in this manual.

40

Omnis Help

Omnis Help
In design mode, Omnis provides many different types of help: tooltips and helptips over
toolbar controls; help text for the main menus shown in the status bar at the bottom of the
Omnis application window; and a fully context-sensitive Help system, available by pressing
F1 or via the Help menu. Omnis also provides Whats This? help for individual functions
and commands while youre working in the Method Editor; Whats This type help is not
provided for the main tools in the Omnis IDE. (Note that under Windows Vista you need to
press the Alt key to show the main Omnis menus, including the Help menu, or you can show
it by Right/Ctrl-clicking on the Omnis toolbar and selecting the Menu bar option.)

Under the Contents tab you can drill down to the


topic or object type youre looking for; you can
double-click on an item in the tree to load the
page

Under the Search tab you can type a


command, function, or method name and
Omnis will provide a list of matching topics;
you can double-click an item in the Topic list
to load the page under the Topic tab (as
shown below)

41

Chapter 1The Omnis Environment

You can create your own Help system and add it to your own application; creating your own
help is described in the Omnis Programming manual. Note that the Omnis Help available in
the development version of Omnis is located in the omnis\idehelp folder.

42

Omnis Libraries

Chapter 2Libraries and


Classes
The components for your Omnis application are stored in an Omnis library file. This file
contains all the class definitions that define the data and GUI objects in your application.
The class types available in Omnis include remote forms (web or mobile forms), remote
tasks for handling web communications, schemas for defining your data structures, reports,
and so on.
Classes are predefined structures that control the appearance and behavior of the objects in
your application, and therefore classes are the main components in your library file. You
can create classes using the wizards provided in the Studio Browser, or you can create them
from scratch using class templates. You can create any number of classes in each library file
and modify them at any time while you develop your application. You can check classes in
and out of the Omnis VCS and work on different parts of your library on a collaborative
basis (depending on the license you have).

Omnis Libraries
Each library file contains a number of system classes and preferences that control the
behavior of your library and its contents. A library has certain properties too, which you can
examine and change using the Property Manager.
You can create and open any number of library files and each library can contain any
number of classes. In fact you may want to split your whole application into one or more
libraries and store different types of objects in different libraries. Alternatively, you can
develop your classes, check them into the Omnis VCS and put them into a library file when
you build your final application.

43

Chapter 2Libraries and Classes


To create a new library

Start Omnis and open the Studio Browser; if the Studio Browser is not open you can
press F2/Cmnd-2 to open it
Click on the New Library option in the Studio Browser
Enter a name for the new library in the New Library dialog, including the file extension
.LBS, and click on OK

When you name a new library you can use the file naming standards for the current
operating system. The .LBS file extension is not obligatory, but it will help you distinguish
library files from other types of file. The new library is opened in the Studio Browser and
shown as a single icon in icon view, or as a single line in details view.

Library Properties
A library has a set of properties or preferences that control how it behaves. You can use the
Property Manager to display or change the properties of a library.
To view the properties of a library

Select the library icon or name in the Studio Browser and press F6/Cmnd-6 to open the
Property Manager

or

Right-click on the library icon or name in the Studio Browser

Select the Properties option from the library context menu

The Property Manager displays the properties of the currently selected library. You can
move you mouse over a of the property to display its help text. The library preferences are
displayed under the Prefs tab in the Property Manager.

Library Default name


The $defaultname property stores the internal name for a library used throughout your
application to reference classes. The $defaultname property defaults to the disk file name of
your library, but you can assign any name you want to the property. If you rename the
library file on disk the $defaultname remains the same retaining all class references. If you
are using multiple libraries you should set $defaultname for all your open libraries and use it
to refer to classes outside the current library. If you change the $defaultname property after
you start developing your library, all class references that use it will fail; therefore in a
multi-library system you should set it once before you start adding classes to your library.

44

Omnis Libraries

Multi-library Projects
Omnis lets you structure your application into one or more libraries that you can load either
together or separately. This lets you
break up your application into smaller, less complex subsystems
develop the subsystems in different programming groups or departments
test the subsystems or modules separately
reuse libraries in different applications, mixing and matching reusable code without
modification
Although Omnis always ensures the integrity of objects, there is no built-in locking or
concurrency checking to prevent two users from modifying the same object. If more than
one user opens an object in design mode, the last one to close the object overwrites the
changes made by the other users. There is no way to ensure that changes made to an object
are seen by other users before the library is reopened: objects are cached in memory and it
is not possible to predict when Omnis will discard an object from the cache. In a team of
developers you should therefore use the Omnis VCS.

Omnis VCS
The Omnis VCS provides you with a full-featured version control system for your Omnis
libraries and other components. If you put your application under version control, you
eliminate the inherent risks involved in group development. See later in this manual for
details about the Omnis VCS.

Comparing Classes
The Studio Browser includes a tool that lets you compare classes in two different versions
of the same Omnis library or different revisions of the same class in a VCS project. The
Compare Classes tool lets you compare all the classes in one library or VCS project or
individual classes. To use the new tool, click on the Compare Classes option in the Studio
Browser.

45

Chapter 2Libraries and Classes

Default Classes
When you create a new library in Omnis, it contains certain default classes including a task
class called Startup_Task and various System Classes that control the behavior and
appearance of your library. As you begin to prototype your application, you dont need to
modify the default classes, but this section gives you a brief overview of how they affect
your library.

The Startup task


When you create a new library it contains a task class called Startup_Task. When you open
your library on the desktop (local runtime environment) the startup task is opened and the
initialization code within it is run automatically. Therefore if you want your library to do
something in particular when it starts up, you put the code to do it in the startup task.
The Startup_Task is not relevant for web or mobile apps, since the end user will be opening
your application in their browser or native wrapper: any initialization of a web or mobile
app should be done in the initial remote form to open in the browser.
Each library has a preference called $startuptaskname which stores the name of the startup
task, and is set to Startup_Task by default. To change the task that is run when your library
opens, you need to change this property, but in most cases you can leave it set to
Startup_Task.
The startup task has a special function when you are designing your library and adding other
classes and variables to your library. At present you dont need to worry about the startup
task or do anything to it, you can proceed to create your data and GUI classes in your
library.

System classes
Every new library contains a number of System Classes, contained in a folder called
System Classes. You can hide or show them using the Class Filter option in the Studio
Browser. Many of the system classes relate to desktop apps only, and are therefore
irrelevant for web and mobile apps.
System classes are special types of class that hold information about the Omnis
environment, including field styles, fonts, input masks, and external components. You can
edit some of the system classes to change the way Omnis behaves. The settings for these
tables are stored for each separate library. You can copy system classes from one library to
another and you can edit them, but some options available for normal classes are not
available for these tables. Like other classes, you can check system classes into the Omnis
VCS.

46

Default Classes
The system classes are as follows.
Name

Description

#BFORMS

boolean formats; these specify the format of Boolean fields


allowed in your library
date formats; these specify the format of short date, and date and
time values
the external components available in the current library: described
in the External Components chapter
the icon file for the current library; described in the Library Tools
chapter
input masks for data entry fields
number formats for numeric data entry fields
the master and user passwords for your library
character styles for window and report fields, and text objects; you
can print a list of styles by right-clicking on the class and selecting
Print Class
text formats; these specify the format of character fields
font table for report classes under Windows, Mac OS Classic,
Linux/Unix or Mac OS X; using these system classes you can map
fonts used on report classes under one operating system to fonts
appropriate for the other OS
font table for window classes under Windows, Mac OS Classic,
Linux/Unix or Mac OS X; using these system classes you can map
fonts used on window classes under one operating system to fonts
appropriate for the other OS

#DFORMS
#EXTCOMPLIBS
#ICONS
#MASKS
#NFORMS
#PASSWORDS
#STYLES

#TFORMS
#WIRFONTS
#MARFONTS
#UXRFONTS
#MXRFONTS
#WIWFONTS
#MAWFONTS
#UXWFONTS
#MXWFONTS

You can edit a system table by double-clicking on it in the Browser. For example, you can
double-click on #DFORMS which opens the Date formats dialog showing all the date
formats for the current library.

47

Chapter 2Libraries and Classes

Class Types
There are several different types of class in Omnis, each one performing a particular
function in your library, or your app as a whole. In general, classes are either Data classes
or GUI classes, depending on whether they define the data structures or certain visual
elements in your application. The types of class are:
Schema
data class that defines a server table and its columns on your server database
Query
data class that defines one or more server tables and their columns on your server
database
Table
data class that maps to a schema class and contains default methods for processing your
server data
Remote form
GUI class that defines the forms to be displayed on web or mobile devices (JavaScript
Client, or iOS Client)
Remote task
class that controls remote form instances (web forms) and maintains the connection
between a client and the Omnis Server in web applications
Object
class that contains methods and variables defining your own structured data objects
Report
GUI class that defines the reports you can print in your application (Desktop/Local
apps only)
Task
class that contains or controls other instances, and handles events in your application
(Desktop/Local apps only)
Code
class that contains methods you can use throughout a library, for example, a menu and
toolbar in a desktop application could access the same methods stored in a code class
The following classes are used for Desktop/Local applications only, therefore you
should not use them for web and mobile apps:
File
data class that defines the structure of a file (the Omnis equivalent of a table) in an
Omnis data file

48

Class Templates and Wizards


Search
class that filters the data stored in an Omnis data file
Window
GUI class that defines the data entry windows for Desktop apps only (cannot be used
for web and mobile apps)
Menu
GUI class that defines standard pulldown, popup, and hierarchical menus for Desktop
apps only
Toolbar
GUI class that defines the toolbars for Desktop apps only
The following class can only be used with the Omnis Web Client plug-in:
Remote menu
GUI class that defines context menus for Omnis Web Client based apps only

Class Templates and Wizards


The Studio Browser gives you the option of creating new classes using the blank or empty
class templates, or using the class wizards which let you build fully functional classes
complete with data fields and methods created for you automatically. These methods of
creating classes are accessed using the list of hyperlink Options in the Studio Browser.

New Class templates


The New Class option in the Studio Browser (available when a library is selected) lets you
create a blank or empty class that you can build and modify from scratch. Templates are
available for all the different class types in Omnis. If you are new to Omnis or you want to
prototype your application quickly, you should use the class wizards. When you are more
experienced or you want to create classes from scratch then you can use the class templates.

Class Wizards
The Class Wizards option in the Studio Browser (available when a library is selected) lets
you create fully functioning classes based on the selections you make during the wizard, and
in the case of GUI wizards, the class you are building can be linked to other classes in your
library. The class wizards are good for building or prototyping your application very
quickly and save you building classes from scratch. You can create a JavaScript remote
form based on a schema class in your library using the SQL JavaScript Remote Form
wizard.

49

Chapter 2Libraries and Classes

Data Classes and Wizards


Depending on the type of data you want to enter or retrieve in your client application you
will need to define certain structures in your library to handle this data. These structures are
stored in your library file as data classes.
This section introduces schema, query, table, file, and search classes. All these classes are
covered in greater detail in the Omnis Programming manual.

Accessing SQL databases


If you want to handle data from a SQL-compliant DBMS you must create Omnis schema
and/or query classes that map to the table and column structures on your server database.
You can create schema classes from scratch or you can create them automatically from the
tables on your database server using the SQL Browser (the Tutorial shows you how to do
this).

Data type mapping


When creating schema classes you need to choose column data types that map directly to
the tables or views on your server database. To do this successfully, you need to choose the
data type for each column that best represents the type of data in your database server. See
the chapters on client/server programming in the Omnis Programming manual for more
information.

Omnis Datafiles
If you want to store and retrieve your data using a non-client/server setup, you can store it in
an Omnis data file. In this case you need to design the structure for your data using Omnis
file classes. In addition, you can use an Omnis search class to filter the data stored in an
Omnis data file.

50

Omnis Data Types

Omnis Data Types


This section describes in detail the standard data types you can use to represent data in
Omnis. Choosing the right type for your data ensures that Omnis will do the right thing in
computations requiring conversion. It also lets Omnis validate the data as you enter or
retrieve it. Some of the basic data types have subtypes, or restrictions of size or other
characteristics of the data that give you finer control over the kind of data you can handle.
The following data types are available.
Field or Variable
Type

Description

Character

standard character set sorted by ASCII value

National

standard character set sorted by national sort order

Number

multiple types for representing integers, fixed point and


floating point numbers

Boolean

single-byte values representing true or false values, or their


equivalents

Date Time

multiple types for representing simple dates and times, or


composite date and times, between 1900 and 2099 to the
nearest hundredth of a second

Sequence

proprietary data type for numbering Omnis data file records

Picture

stores color graphics of unlimited size and bit-depth in


platform-specific format or in a proprietary shared picture
format

List

structured data type that holds multiple columns and rows of


data of any type

Row

structured data type that holds multiple columns of data in a


single row

Object

your own structured data type based on an object class

Binary

stores any type of data in binary form, including BLOBs

Item Reference

stores the full notation of an object in your library or Omnis


itself

Field Reference

passes a reference to a field (parameter variables only)

Object Reference

lets you create an object instance of local, instance, class or


task variable scope

51

Chapter 2Libraries and Classes

Character
Character data can contain characters from any of the various single-byte standard character
sets. You can define a Character column of up to 10 million (10,000,000) bytes in length.
Character columns or fields generally correspond to SQL VARCHAR data and have a
varying length format.
In Omnis character data is sorted according to its ASCII character set representation, not the
server representation. The ASCII character set sorts any upper case letter in front of any
lower case letter. For example, these character values
adder, BABOON, aSP, AARDVARK, Antelope, ANT

are sorted as
AARDVARK, ANT, Antelope, BABOON, aSP, adder

National
Like Character data, National data can contain characters from any of the various singlebyte standard character sets. You can define a National column of up to 10 million
(10,000,000) bytes in length. However, when you sort National data, Omnis sorts the values
according to the ordering used by a particular national character set.
The ordering for the English language follows: A, a, B, b, C, c, D, and so on. For example,
if the previous values were values of a national column or field, Omnis would sort them as
follows:
AARDVARK, ANT, Antelope, adder, aSP, BABOON.

If you store data in an Omnis data file, Omnis stores a copy of the ordering in the file along
with the data. If you use the data file on another machine, Omnis preserves the original
ordering.

52

Omnis Data Types

Number
A number variable can be an integral or floating point number having various storage and
value characteristics, depending on its subtype. The following table summarizes the
different subtypes for numbers.
Number type
(dp = "decimal
places")

Storage
(bytes)

Range

Integer
Short integer

0 to 255

32 bit integer

-2,000,000,000 to +2,000,000,000

64 bit integer

-9,223,372,036,854,775,808 to
+9,223,372,036,854,775,807

Short 0 dp

-999,999,999 to +999,999,999

Short 2 dp

-9,999,999.99 to +9,999,999.99

Floating dp

approx -1E100 to +1E100 (16 significant digits)

Number 0 dp

-999,999,999,999,999 to +999,999,999,999,999

Number 1 dp

-99,999,999,999,999.9 to +99,999,999,999,999.9

Number 2 dp

-9,999,999,999,999.99 to +9,999,999,999,999.99

Number 3 dp

-999,999,999,999.999 to +999,999,999,999.999

Number 4 dp

-99,999,999,999.9999 to +99,999,999,999.9999

Number 5 dp

-9,999,999,999.99999 to +9,999,999,999.99999

Number 6 dp

-999,999,999.999,999 to +999,999,999.999,999

Number 8 dp

-9,999,999.999,999,99 to +9,999,999.999,999,99

Number 10 dp

-99,999.999,999,999,9 to +99,999.999,999,999,9

Number 12 dp

-999.999,999,999,999 to +999.999,999,999,999

Number 14 dp

-9.999,999,999,999,99 to +9.999,999,999,999,99

Number

File Classes and Integers


You can use 64 bit integers in file classes, provided that a field (column) is not indexed. In
Integer subtype droplist in the file class editor, the 64 bit subtype is available but only when
the field is not marked as indexed, otherwise if the field is indexed 64 bit is not present: the
64 bit subtype is not allowed in compound indexes either. The notation to manipulate file
classes and indexes does not allow 64 bit integers to be used for indexed fields.

53

Chapter 2Libraries and Classes

Floating Point Numbers


There are many pitfalls in using floating point numbers in programming. Computers do not
represent these numbers exactly, only approximately within the precision of the machine.
This can lead to all kinds of anomalous problems with comparison of values, particularly
with equality comparisons. Two floating point numbers may differ by an infinitesimal
amount depending on the technique used to generate the values, even though logically they
should be the same.
In general, you should not use equality comparisons with floating point numbers. If you are
working with fixed-point data such as money values, use scaled integers for comparison
and arithmetic.
For example, instead of comparing two floating point variables F1 and F2 containing the
amounts $5.00 and $10.00, compare two integer variables I1 and I2 containing 500 and
1000. Display I1 * .01 when you need a decimal value. You can also use the rnd() function
to round the numbers to a certain number of decimal places before comparing them.

Boolean
The boolean data type represents single-byte values of true (yes), false (no), empty, or null.
You should take care to give each Boolean column or field an initial value, because Omnis
initializes boolean data to empty, not NO or null.
When used in a data entry field in a window, boolean data is treated as three characters in
which any data entry is interpreted as a YES or NO. A `Y', 'YE' or 1 is seen as YES while
an 'N' or 0 will suffice for No. If the field is a check box, you enter the boolean value by
clicking on the box. If you don't initialize the field and the user does not click on the box,
the field has an empty value.
You can use boolean values in expressions. The numeric value is 1 for Yes values and 0 for
No and empty values. NULL values are treated as undefined in numeric calculations. For
example, (null+1) is null and (null>1) is null.
When converted to character strings, Boolean columns or fields can take values "YES",
"NO", "NULL", or empty, "". In some cases, for example when setting up search criteria,
you can enter values other than these for a Boolean field; in this case, Omnis converts them
and matches them with empty. Thus, for example, the value 'FALSE' is converted to empty,
as are values like SAM, HAPPY, and so on.

54

Omnis Data Types

Date time
The date and time group of data types contains three basic subtypes: a four-byte Short date,
a two-byte Short time, and an eight-byte Long date and time. The following table
summarizes the date and time subtypes.
Date Time
subtypes

Storage
(bytes)

Range

Short date

1900..1999

Short date

1980..2079

Short date

2000..2099

Short time

Minute resolution

Date time(#FDT)

Formatted #FDT, to
centiseconds

Date time(D m Y)

Formatted D m Y, to
centiseconds

Note that the display of dates depends on the settings in the #DFORMS system table. Also
the long date and time subtypes are identical in value, only displaying differently in window
fields.

Short Date
The short date type spans the range JAN/1/0000 to DEC/31/9999. There are three specific
built in ranges: 1900 to 1999, 1980 to 2079, and 2000 to 2099. By choosing the appropriate
range, you can enter just two digits for the year and Omnis recognizes the century correctly.
For example, if you select the range as 2000 to 2099, a date you enter as 7,12,57 will be
read as 7,12,2057 rather than 1957. To enter a date outside the three specific year ranges,
you need to set up your own date display format.
Omnis accepts dates in different formats automatically, with the exact format depending on
whether your system is US or European. For example, you could enter the 7th of December,
1998, as any of the following strings.
US system

European system

12-7-98

07-12-98

12/7/98

7/12/98

12%7%98

7%12%98

DEC 7 98

7 DEC 98

You can use any character to delimit the day and month figures. If you don't specify the year
or month and year, Omnis assumes the current year or month and year, respectively.

55

Chapter 2Libraries and Classes


Omnis supports three kinds of date arithmetic in expressions.
Addition of days:
Date + Days = Date (forward)
Subtraction of days:
Date - Days = Date (back)
Subtraction of dates to yield number of days between the dates:
Date1 - Date2 = Number of Days between the dates
Omnis uses the string variable #FD to define the display format of dates. There are also
several date functions that let you manipulate date strings.

Short Time
Short time types have two-byte values in the form HH:NN. The range of possible time
values is from 00:00 to 23:59.
You can use time in expressions. Omnis automatically converts the time into numeric values
using the conversion HH*60+NN, giving the total number of minutes. The #FT string
variable controls conversions between time and string types.

Long Date and Time


The combined Date Time type can hold a complete date and time to 1/100th second. It has
various subtypes depending on the display format you select (stored in #FDT) and uses 8
bytes when stored in a data file.

Date and Time Calculations


The numeric value of a date or time variable in an expression depends on the format string
for that variable. So, if DATE1 has date format string H:N and DATE2 has date format
string H:N:S, DATE1 has a numeric value equal to the number of minutes since midnight
and DATE2 has numeric value equal to the number of seconds since midnight. It follows
that DATE1+1 adds 1 minute to DATE1 and DATE2+60 adds 1 minute to DATE2.
Addition and subtraction involving two date/times cause the numeric value of each to adjust
so that they are both based on a common denominator. Thus DATE1-DATE2 returns a
numeric value equal to the correct difference between the two times in seconds. However,
DATE1*1-DATE2*1 loses the information that DATE1 and DATE2 represent date times
and returns a meaningless difference between the DATE1 value in minutes and the DATE2
value in seconds, for example, 500 minutes - 600 seconds.
Note that calculations involving combined dates and times do not work properly if the date
part is before 1900. Comparisons between two datetimes with different date format strings
work properly.
When you compare parts of dates, for example, the month part of a date, dtm('11 June 98'),
Omnis compares the string representation of the month unless some calculation forces it to
use the number representation of the month. Thus the expression dtm('11 Dec 98') is less
56

Omnis Data Types


than dtm('11 June 98') because 'D' is before 'J' in the alphabet. To force a correct numeric
comparison, add 0. For example
If dtm('11 June 98')<(dtm('11 Dec 98')+0)
OK message {6 is less than 12}
End If

You should try to use straight date comparisons if you are comparing full dates. Dont try to
convert them into integers or other types of data. Let Omnis do the work for you.

Century Ranges for Dates


When entering data into a date time field or variable without specifying the century, the date
normally defaults to be within the hundred year range starting with 1st January 1980.
However, you can specify the start of the hundred year default range as a library preference
with the option of overriding it for individual date types.
You can use the $centuryrange library preference to set the default century range
($clib.$prefs.$centuryrange), a four digit year is specified which defaults to 1980. So if, for
example, $centuryrange is set to 1998, dates for which no century is entered default to
between 1st January 1998 and 31st December 2097.
In addition, the 30 date formats which are stored in the #DFORMS system table can include
the century range by including a four digit year at the end of the date format. For example,
date formats starting at 1st January 1998 include D m Y H:N:S 1998 and YMD 1998.
This can be used to override $centuryrange for particular date types.
The same mechanism can be used to control the conversion of character values to dates
using the dat() function, for example:
Do dat(charvar,D m Y 1998) Returns datavar

Century ranges are used when dates are entered from the keyboard or when a character
string is converted to a date. If you enter a date that includes the century, the century range
is ignored. Century ranges do not affect how a date value is stored or displayed, Omnis
always stores the full date including the century.

Sequence
Every time Omnis inserts a new record into an Omnis data file, it assigns a unique number,
a record sequencing number or RSN to that record. There is a special data type, the
sequence, for this type of data. Each RSN references a location in the data file. If you delete
a record, Omnis does not reuse the RSN. The RSN is stored as a 32-bit integer so its
maximum value is 2^32-1, which is approximately 4,295 million! The sequence type is not
applicable to client/server data.
Omnis assigns record sequencing numbers (RSNs) according to the following rules:
The first record in a file has RSN 1, the second record RSN 2, and so on

57

Chapter 2Libraries and Classes


An RSN is never used again, even though the record may no longer exist
A window field with sequence type provides a way for the user to see the RSN for any
record in an Omnis data file, even though they cannot change it.
Omnis assigns the RSN just before saving the record in the data file, so it is not available
for any calculations prior to the Update files command.

Picture
The picture data type holds color graphics with a size limited only by memory. The space
each picture consumes depends on the size and resolution of the image. The internal storage
of a picture is either in native format (Windows bitmap or DIB or metafile or Macintosh
PICT) or in Omnis shared color format. Server databases store picture data as binary
objects (BLOBs).

List
The list is a structured data type that can hold multiple columns and rows of data. A list can
hold an unlimited number of lines and can have up to 400 columns. When you create a list
variable you set the type of each column. The data type of each column in your list can be
any one of the other data types including Character, Number, Date, Picture, and List: Yes,
you can even have lists within lists!
Omnis makes use of the list data type in many different kinds of programming tasks.
Normally you would create a variable with list data type and build your list in memory from
your server data or Omnis data file. Then you could use your list data as the basis for a grid
or list field on a window, or you could use it to generate a report.
You can store lists in Omnis data files directly. To store a list in a SQL table on a server,
you can map it to a binary field of some kind.

Row
The row is a structured data type, like a list, that can hold multiple columns and types of
data, but has one row only: it is essentially a list type with a single row. A row can have up
to 400 columns. When you create and define a row variable, you set the type of each
column. As with lists, the data type of each column in your row can be any one of the other
data types including Character, Number, Date, Picture, List, and Row.

Object
Object classes let you define your own structured data objects. Their structure, behavior,
and the type of data they can hold is defined in the variables and methods that you add to
the object class. A variable with object type is a variable based on an object class: the
subtype of the variable is the name of an object class. For example, you can create an

58

Omnis Data Types


instance variable of Object type that contains the class and instance variables defined in an
object class.
When you reference a variable based on an object class you create an instance of that object
class. You can call its methods with the notation VarName.$MethodName(). For an object
variable the initial value contains the parameters which are passed to $construct() for the
class when the instance is constructed. The instance lasts for as long as the variable exists.
You can store object instances in a list. Each line of the list will have its own instance of the
object class. You can store object variables, and hence their values, in an Omnis data file or
server database which can store binary values. If an object variable is stored in a data file
the value of all its instance variables are stored in binary form. When the data is read back
into Omnis the instance is rebuilt with the same instance variable values.

Object reference
The Object reference data type provides non-persistent objects that you can allocate and
free using notation. Non-persistent means that objects used in this way cannot be stored on
disk, and restored for use later.
You can use the Object reference data type with local, instance, class and task variables. It
has no subtype. To create a new Object instance, referenced by an Object reference
variable, you use the methods $newref() and $newstatementref(). These are analogous to the
$new() and $newstatement() methods, and they can be used wherever $new() and
$newstatement() can be used.
Refer to the Omnis Programming manual for information about using object references.

Binary
The binary type can store structured data of unlimited length up to your maximum available
memory. Omnis does not know anything about the format and structure of the data in a
binary column or field. In this type of column or field you could place, for example, desktop
publishing files, MIDI system exclusive files, CAD files, and so on. You could store the
definition of an Omnis class in a binary field.
Binary data corresponds to binary large objects (BLOBs) on most database servers.

Item reference
You can use a variable of type Item reference to store an alias or reference to an object in
Omnis or in your library. You assign the notation for the object to the item reference
variable using the Set reference command. You can use an item reference variable in
calculations or expressions which saves you having to quote the full path to the object. You
can also use an item reference variable with the Do command to return a reference to the
object or instance created by the command.

59

Chapter 2Libraries and Classes

Field reference
You can pass a reference to a field using the field reference data type, available for
parameter variables only. A parameter variable with the field reference type must have a
valid field in the calling method. Once the field reference parameter variable is set up, a
reference to the parameter is the same as using the field whose name is passed.

Nulls and empty values


A variable or column of any data type can be NULL. This means the value is unknown or
irrelevant, and that there is therefore no way to operate on the column value. A null value is
distinGUIshable from an empty value, which represents empty or uninitialized data.
When defining a file class, you can specify that a field Can Be Null or Cannot Be Null.
This controls the handling of rows written to Omnis data files only and is irrelevant for
client/server data, since it doesnt prevent fields from getting null values in Omnis
calculations. Null data from a SQL database corresponds to null values in Omnis fields and
variables, and null values are sent to a server database as SQL nulls.
You can use the hash variable #NULL to represent null values in calculations. For example,
to set a variable to null:
Calculate LV_Variable as #NULL

The result of arithmetic, comparison, and logical operators on null data is always null. With
string functions such as con() and jst(), however, Omnis translates null to empty. The
isnull() function returns kTrue if the value is null and kFalse if not.
When you use an Omnis sort on columns or variables with nulls, Omnis sorts the nulls first
and separately from the empty values (or, for a descending sort, last). In a sorted report the
nulls come first and do generate a break.
When exporting records in a text format, null values export as an unquoted string NULL,
unless a particular format doesnt support nulls. In this case, Omnis translates the null to
empty. Occurrences of this unquoted string in an import file import as nulls.

Formatting strings and input masks


You can further structure Character, National, Date, and Boolean data for display in
window fields using formatting strings and input masks: see the Window Programming
chapter in the Omnis Programming manual for details.

Current Record Buffer


The Current Record Buffer, or CRB, is an area of RAM, that Omnis uses to hold your
current data. For example, if you are accessing a number of file classes or a SQL view, the
CRB holds the current record or data for those files or view.

60

Schema classes

Schema classes
A schema class is a type of data class that represents a table or view on your server
database. A schema class contains the name of the server table or view on your server, and a
list of column names and Omnis data types that map directly to the columns in your server
table or view. The Omnis data types defined in a schema class should map to the equivalent
server types, and the column names must conform to any conventions about case used by
the server. For example, if the server column names are case sensitive, the column names in
your schema class must be in the correct case.
Schema classes do not contain methods, and you cannot create instances of them. You can
however use a schema class as the definition for an Omnis list using the
$definefromsqlclass() method, which lets you process your server data using the SQL
methods against your list.
To create a new schema class

Select your library in the Studio Browser

Click on the New Class option, then click on the Schema option

Name the new class and press Return

To edit the class, double-click the class in the Studio Browser

The schema editor lets you enter the name of the server table or view and the column
definitions You can move from column to column in the editor either using the Tab key, by
clicking in the column, or with the keyboard Up and Down arrows.
Having created a schema (or query) class, you can use the SQL Form Wizard to create a
SQL form based on the class to view and enter data into your server database.

Creating schema classes automatically


You can create a new schema class from scratch, as described above, or you can create one
based on a table on your SQL server database. To do this, you can drag the server table
from an open session in the SQL Browser onto your library in the Studio Browser. This
process creates a schema class that maps to your server table (or view) automatically, and
ensures that the data classes in your Omnis library map to the data on your server exactly.
You can then use the SQL Form Wizard (described in the GUI wizard chapter) to create a
form based on the automatically generated schema class.

61

Chapter 2Libraries and Classes

Query Classes
A query class is a type of data class that lets you combine one or more schema classes or
individual columns from one or more schemas, to give you an application view of your
server database. A query class contains references to schema classes or individual schema
columns.
Query classes do not contain methods, and you cannot create instances of them. You can
however use a query class as the definition for an Omnis list using the $definefromsqlclass()
method, which lets you process your server data using the SQL methods against your list.
To create a new query class

Select your library in the Studio Browser

Click on the New Class option, then click on the Query option

Name the new class and press Return

To edit the class, double-click the class in the Studio Browser

Enter the names of the schema classes or schema columns

When you open the query class editor the Catalog pops up which lets you double-click on
schema class or column names to enter them into the query editor. Alternatively, you can
drag schema class or column names into the query editor. Furthermore, you can reorder
columns by dragging and dropping in the fixed-left column of the query editor, and you can
drag columns from one query class onto another. You can also drag a column from the
schema editor to the query editor.

Table Classes
A table class provides the interface to the data modeled by a schema or query class. When
you create a list based on a schema or query class, a table instance is created automatically
which contains the default SQL methods. You should only need to create a table class when
you want to override the default methods in a table instance, or you want to add methods to
a table. A table class contains the name of the schema or query class it uses, and your own
custom methods that override or add to the default table instance methods.
To create a new table class

62

Select your library in the Studio Browser

Click on the New Class option, then click on the Table option

Table Classes

Name the new class and double-click on it to edit it

You add methods to a table class in the method editor, and change its properties in the
Property Manager. To associate a table class with a schema or query class, you need to set
its $sqlclassname property to the name of a schema or query class.
Like Schema and Table classes, you can use a table class as the definition for an Omnis list
using the $definefromsqlclass() method, which lets you process your server data using the
methods you added to the table class. See the Omnis Programming manual for further
details about the SQL lists and their methods.

63

Chapter 3Omnis Programming

Chapter 3Omnis
Programming
Omnis Studio has a powerful programming environment that lets you create almost any type
of enterprise or web application. The Omnis programming environment contains hundreds
of 4GL commands and functions, as well as a low-level scripting language, called Omnis
Notation, that allows you to manipulate objects dynamically in the runtime environment. To
program in Omnis, you must consider the following things:
Variables
variables are the principal data container in Omnis; most objects in Omnis can contain
variables, but their scope and the kind of data they can contain depends on the type of
variable; you can use the method editor to add variables to an object; the definition and
dynamic manipulation of variables is at the heart of programming
Methods
methods are pieces of Omnis code contained within the objects in your application,
each performing a particular operation specific to the object or the application as a
whole; creating and modifying methods in your library is key to creating an application.
Events
almost all user actions in Omnis generate an event; when an event occurs a message is
sent to the object in which the event occurred; you need to write methods behind the
objects in your library to handle the events.
Tasks
when your application runs in Omnis many object instances are created, such as
windows, reports, and web forms; these instances are opened and handled within a task.
Omnis creates a default task, but you can create your own tasks that allow you to
handle the objects in your application.
All the above topics are covered in this chapter. You create and modify methods in Omnis
using the method editor.

64

Variables

Variables
Variables can hold different types of data and are visible in different parts of your
application depending on their data type and scope. For example, if you create a variable of
list data type in a window class, the list variable and hence its data is visible within the
window class and all its instances, but is not accessible elsewhere in your library. The data
types available in Omnis are described in detail in the Introducing Omnis manual.

Declaration and Scope


A variable may be global, accessible from all parts of your application, or it may have its
scope restricted to certain areas so that it cannot be referred to from elsewhere. By declaring
variables in the proper scope, you limit the potential for arbitrary connections across your
application and thus reduce the potential for error and the complexity of your application.
The following table lists the different kinds of variables and their scope. It also shows when
they are initialized and destroyed.
Variable

When Initialized

When Destroyed

Scope

Parameter

on calling the
method

returning to the calling


method

the recipient method

Local

on running the
method

on terminating a
method

the method

Instance

on opening an
instance

on closing the instance

a single instance of a
class

Class

on opening a
library

on clearing class
variables or closing a
library

the class, and all


instances of the class

Task

on opening an
instance of the task

on closing the task


instance

the task, and all its


classes and instances

Hash

on starting Omnis

on quitting Omnis

global

Apart from hash variables which are permanently built into Omnis, you must create all
variables with the appropriate type and scope in the objects in your library using the method
editor. After you have declared them, variables that are in scope are listed in the Catalog.
You can remove a variable using the Delete Variable option in the variable pane context
menu. Declared variables are removed from memory when they are destroyed.

65

Chapter 3Omnis Programming

Parameter Variables
You can use a parameter variable to receive a value in a method, for example, a value that
has been passed to the method using the Do method. You would normally do something
with the value in the method and possibly return a new value. Parameter variables are
visible within the called or recipient method only. They are initialized when the method is
called, and cleared when the method returns to its caller.

Local Variables
Local variables are local to the method. You can refer to the variable within that method
only. Local variables are initialized when the method begins execution, and are cleared
automatically when the method terminates.

Instance Variables
Instance variables are visible to the instance only, that is, all methods and objects in the
instance. You can define an instance variable only for classes that can be opened or
instantiated, that is, tasks, tables, windows, remote forms, remote tasks, reports, menus,
toolbars and object classes. Note that you cannot declare instance variables in code classes.
There is a set of the declared instance variables for each instance of a class: these are
initialized when the instance is constructed and cleared when the instance is destructed.

Class Variables
Class variables are visible within the class and all its instances. You can declare class
variables for tasks, tables, windows, reports, menus, toolbars, and code classes. Any object
or method in the class can refer to a class variable, and all instances of the class also have
access to the class variable.
Class variables are not automatically cleared from memory. You can remove them from
memory by closing the library containing the class, or using the Clear class variables
command.

Task Variables
Task variables are visible within the task, all its design classes and instances. In practice,
you can refer to a task variable from any method within any class or instance that belongs to
the task. Omnis initializes task variables when you open the task: for the Startup_Task this
is when the library opens. Note that you cannot declare a task variable for a class until you
have set the $designtaskname property for the class.

66

Variables

Hash Variables
Omnis has a built-in set of global variables, called hash variables since they start with the
symbol "#". You can view them in the Catalog (F9/Cmnd-9). Hash variables are global,
unlike any other variables, so all libraries have access to them. The advantage of having
global variables is that you can use these variables to pass data between libraries in an
application. The disadvantage is that any data you place in hash variables remains there
when you switch between libraries or combine libraries, with potentially unpredictable
results.

Adding a Variable
You add variables to a class or object in the variable pane of the method editor. If the
variable pane is not visible you can show it using the View>>Show Variable Panes menu
option on the method editor menu bar.
The tabs in the variable pane let you define task, class, instance, local and parameter
variables; note that the local and parameter tabs only appear after you have added or
selected a method in the method editor. You can add up to 400 variables of each type to the
current object, including 400 local and parameter variables for each method in the current
object. The name, type, subtype, and initial value of each variable is listed in the variable
pane. You can size the columns in the variable pane by sizing the column headers.
You cannot declare a task variable within a class until you have set the $designtaskname
property for the class: see the section below on Adding Task Variables.
To add a new variable

Open the class in which you want to add the variable

Right-click on the background of the class to open the class context menu

Select the Methods option to open the method editor

Choose the tab for the type of variable you require

Click in the blank field under the Variable column header

Enter the name of the variable

or

Right-click in the variable pane to open the variable context menu


Choose Insert New Variable and click in the variable name to edit it, or type over the
new variable name if it is selected (see Variable naming below)

67

Chapter 3Omnis Programming

Tab to the Type box and choose the type from the droplist using the mouse or arrow
keys

or when the focus is in the Type box

Type the first letter(s) of a data type to select it, for example, you can type nu to
select the Number data type, or b for Boolean and bi for Binary type

For Number and Date Time variables

Tab to the Subtype box and choose a subtype; again, you can type the first letter(s) of a
subtype, for example, for Numbers you can type L to select the Long Integer subtype

You can enter an initial value or calculation for all types of variable. The initial value
allowed for a variable depends on its type. See Variable Values below.

Variable Naming
Variable names can be up to 255 characters long, although in practice you should keep them
as short but descriptive as possible. When you name a variable you should prefix its name
with one or more letters to indicate its scope. For example, parameters variables can begin
with the letter p, local variables lv or just the letter l, instance variable iv or just the
letter i, and so on.
When two or more types of variable use the same variable name, a reference to that variable
could be ambiguous. In a situation where more than one variable of the same name exists,
Omnis automatically uses the variable with the smallest scope. Therefore, it is possible,
though not good practice or recommended, to have local, class, and task variables called
"MYNAME". As Omnis resolves ambiguity, a reference to MYNAME will refer to the
local variable if it exists for the current method. To avoid all ambiguity you should use a
naming convention similar to the one described above

Adding Local and Parameter Variables


Local and parameter variables are inserted into the currently selected method. Therefore to
insert these variables for a particular method, you need to select the method before inserting
local and parameter variables.
Parameter variables receive values from a calling method in the order that they appear in the
variable pane. You can reorder parameter variables by dragging them into position in the
variable pane. Click and drag the fixed-left column or row number for a parameter variable
in the list.
Normally you must declare all types of variable, including local variables, in the variable
pane before you can use them in your code. However you can declare a special type of local
variable in your code without first declaring it in the method editor. To declare such a
variable, prefix the variable name with %% to create a string variable, or prefix the variable
name with % for a numeric variable of Floating point type. You can type such variable

68

Variables
names directly into your code in the method editor, at which time their names are added to
the Local variables pane.

Deleting Unused Variables


The context menu of the Variable pane has the option Delete Unused Variables...,
available by Right-clicking on the variable pane away from a variable line. When selected,
it opens a dialog from which you can select variables to delete. The dialog displays the
variables of the current type displayed in the variable pane, which are potentially unused.
This means the variables could still be in use, for example, they could still be used in
subclasses or notation.

Adding Task Variables


To add a task variable for a class you have to set its $designtaskname property. In most
cases, the design task for a class is specified as the Startup_Task by default. You can change
it using the Property Manager or the notation. The design task for a class is ignored at
runtime.
To set up the design task for a class

Click on the class in the Browser

Display the Property Manager or bring it to the top (F6/cmnd-6)

Click on the droplist in the $designtaskname property to view the current tasks

The list of tasks will contain a Startup_Task, and any tasks you may have created.

Select the design task by clicking on it

You will now be able to define task variables for this class.

Changing the Scope of Variables


You can change the scope of a variable at any time by dragging the variable from one
variable pane to another. For example, you can change a class variable into an instance
variable by dragging and dropping it onto the instance variable tab. Note you cannot change
the scope of task variables.

Variable Values
When you declare a variable in the variable pane of the method editor you can assign it an
initial value. The first time a variable is referenced in a method, Omnis assigns the specified
initial value to the variable. You can set the initial value to be a number, string, calculation,
some notation, an Omnis constant, or another variable name. In the latter case, when you
first use the variable it gets the value in the other variable, regardless of the order of
declaration.

69

Chapter 3Omnis Programming


For class variables only, the Clear class variables command clears the current values in all
class variables and resets them to their initial values.
You can set the initial value of parameter variables, which in effect gives them a default
value, but when and if a value is received in the method the initial value is overridden. For
example, you may want to assign an initial value of zero to a parameter value to avoid it
being null if a value is not received.

Variable Context Menu


You can lookup and edit the value of any variable or constant in Omnis at any time using its
context menu. You can Right-click on a variable name wherever it appears in Omnis to
open its context menu and view its current value. The Variable context menu displays the
variable name, its current value, which group of variables or class it belongs to, and its type
and length. You can also perform various debugging functions from this menu as well.
If you select the first option in the Variable context menu, Omnis opens a variable window
containing the current contents of the variable which you can edit. Note that you cannot edit
binary variables.

Variable Tips
You can pass the mouse over a variable or constant and a variable tip will pop up
displaying the variables current value. Variable tips are available wherever variable names
appear in Omnis including the method editor and Catalog. However, they are not available
if Help tips are enabled for the tool containing the variable. For some variable types, such as
list or binary variables, the tip may say not empty which tells you the variable has a value,
but it is too long to display.

Viewing Variables in the Catalog


You can view the variables in your library and the current class using the Catalog (press
F9/Cmnd-9 to open it). The Variables pane shows all the Task, Class, and Instance variables
for the current class, plus all Local and Parameter variables for the currently selected
method. Following the Event Parameters group, the Catalog also lists any file classes in
your library. You can enter the name of any variable that appears in the Catalog into your
code either by double-clicking on the name in the Catalog (assuming the cursor is at a
position that can accept input), or by dragging the variable name out of the Catalog into the
method editor.
When you drag a variable from the Catalog, Omnis shows you what type of variable it is
and its name. Note that you can also drag variables from the Catalog and drop them onto
window and report classes to create a data field for the variable.
You can also drag a variable from the variable pane in the method editor to any calculation
or entry field in the command palette. To drag a variable name you need to click and drag
the fixed-left column or row number in the variable list.

70

Methods

Auto Fill Variable Option


When you want to enter a variable in the method editor command palette and you cant
remember its full name, you can type the first few characters of the variable, wait a short
while for a list to appear, and choose the variable from the list that pops up. The list
contains all the variables beginning with the characters you typed. The time it takes for the
autofill option to work is set in the $notationhelptimer Omnis preference (the default is
1000 milliseconds).

Custom Variable Types


You can define your own custom variable types. To do this you have to create a custom
method called $<customatttribute name>.$assign, and then the $type, $subtype and $sublen
properties of the custom variable return their value according to the type of parameter 1 of
$<customatttribute name>.$assign.

Methods
Omnis provides a complete 4GL programming language comprising over 400 commands,
each command performing a specific function or operation. In addition, Omnis provides a
means to manipulate the objects in your library called the notation: this accesses the
standard properties and methods contained in the objects in your library.
A method can contain up to 1024 lines of code. Each method line can contain an Omnis
command, or some notation, or often a combination of these; you can also add comments to
method lines. For example, to open a window from a menu line you only need one
command in your method, that is the Open window instance command, which as the name
suggests opens an instance of a window. A method that connects you to a server database
requires several commands executed in a particular order. You can perform most operations
using the notation and the Do command. For example, you can open a window using the Do
command and the $open() method.
For further details about specific commands and notation used throughout this chapter, see
the Omnis Help (press F1 to open it), or the Omnis Reference manuals. When you start to
program methods you will need to use the debugger which is described in the Debugging
Methods chapter.

71

Chapter 3Omnis Programming

Commands
The following sections outline the more important commands or groups of commands in
Omnis. The commands that you can use in your methods are listed in the command list at
the bottom of the method editor. If the command list is not showing in the method editor
you can show it using View>>Show Command Palette, or by pressing Shift-F6 under
Windows or Shift-Cmnd-6 under MacOS.
Double-click on each group in the command list to get an idea of the full range of
commands available in Omnis.
Each group in the command list contains a number of commands that manipulate a
particular type of object or perform related operations. For example, the Calculations...
group contains the Calculate command that lets you do calculations and assign a value to a
variable, and the Do command that lets you execute and modify objects using the notation.
The Constructs... group contains programming constructs such as If...Else If, Repeat...Until,
and For loops.

The Flag
Some of the commands set a Boolean Omnis variable called the flag, or #F, to true or false
depending on the success of an operation. Other commands test the current value of the flag
and branch accordingly. The Omnis Studio Help documents whether or not a command
affects the flag.

Notation
Omnis structures its objects in an object tree, or hierarchical arrangement of objects and
groups that contain other objects. The complete tree contains all the objects in Omnis itself,
together with your design libraries, classes, and other objects created at runtime. You can
view the complete object tree in the Notation Inspector.
The object at the base of the tree is called $root. The $libs group contains all the current
open libraries and lets you access each library and its classes at design time. The classes and
objects in each library are stored in their own separate groups; for example the $windows
group contains all the window classes in a library. Most of the other groups directly under
$root contain the objects created at runtime when you run your application; for example the
$iwindows group contains all the window instances currently open, or $iremotetasks
contains all the remote task instances currently open.
When you want to reference a particular object, a class or instance perhaps, you must access
the right branch of the object tree. For example, you must access the $windows group to
reference a window class. Whereas, to access a window instance, say an instance of the
same window class, you must reference the window instance via the $iwindows group,
which is contained directly under the $root object.
To facilitate a system of naming or referring to an object in the object tree, and its
properties and methods, Omnis uses a system called the notation. The notation for an object
72

Methods
is really the path to the object within the object tree. The full notation for an object is shown
in the status bar of the Notation Inspector. You can use the notation to execute a method or
to change the properties of an object, and you can use a notation string anywhere you need
to reference a variable or field name.
In the notation all property and standard method names begin with a dollar sign $, and
methods are further distinguished from properties by having parentheses after their name.
Standard objects and group names also begin with a dollar sign. To write the full notation
for an object you need to include each object and group in the path to the object, separating
each object using . a dot. For example, to refer to a window class in a library you would
use the following notation
$root.$libs.LIBRARYNAME.$windows.Windowname

This notation includes $root as the base object, the $libs group containing all the open
libraries, the name of your library, the $windows group containing all the window classes in
your library, and lastly the name of the window itself. If you want to refer to a particular
object on your window you need to add the $objs group and the name of the object
$root.$libs.Libraryname.$windows.Windowname.$objs.Objectname

You can omit certain object names from a notation string to make it shorter, and when you
have only one library open usually you can omit the library name as well. You can omit the
following objects: $root, $constants, $clib, $hashvars, $libs, $extobjects, $tvars, $datas,
$cvars, $files, $lvars, $vals. In most cases therefore, you can refer to an object on a window
as
$windows.Windowname.$objs.Objectname

In addition, there are a number of shortcuts that let you reference objects, without always
referring right back to the $root object, and certain global objects that you can use to make
your code more generic. These are described below.

Item References
To save you time and effort, and to make your code more efficient, you can create an alias
or reference to an object which you can use in place of the full notation for the object. To
do this, you create a variable of type item reference and use the Set reference command to
assign the notation to the variable. The item reference variable can be of any scope, and the
notation can be any valid Omnis notation for an object, a group, or even an object property.
For example
; Declare variable WinRef of type Item reference
Set reference WinRef to Libraryname.$windows.Windowname
; creates a reference to the window which you can use in your code
Do WinRef.$forecolor.$assign(kBlue) ;; changes the window forecolor

You can enter the notation for an object in the initial value field for the item reference
variable. You can also find the full notation for an object in the Notation Inspector and drag
it to the notation field when you enter the Set reference command.
73

Chapter 3Omnis Programming


You can also use an item reference variable to return a reference to a new object, when
using methods to create a new class, instance, or object. Furthermore Omnis contains a
special property called $ref which you can use to return an item reference to an object. Both
these features are used in the section describing the Do command below.

Current Objects
Under $root, Omnis contains a number of global state variables that tell you about how
Omnis is currently executing, or what objects, instances, and methods are currently being
used. These objects provide a shortcut to the current object or instance that is currently
executing. Mostly their names begin with $c, and they include
$cclass
the current class
$cdata
the current open data file
$cinst
the current instance; usually the instance containing the currently executing method
$cfield
the field where the current method is executing
$clib
the current library
$cmethod
the current executing method
$cobj
the current object within a class or instance
$cparmcount
the number of parameters that the caller has passed to the current method
$crecipient
the current recipient of an event; if a custom method is being processed, $crecipient is
the recipient of that method
$ctarget
a reference to the target field, that is, the field which currently has the focus (shows the
caret and is sent keyboard events)
$ctask
the current task; is usually the startup or default task until you open another task
$cwind
the current window instance

74

Methods
$topwind
the topmost open window instance
You can use the current objects in place of the full notation for a specific object to make the
object and its code reusable and portable between libraries. For example, you can use $cinst
in a method within a window instance to refer to itself, rather than referring to it by name
$cinst
; rather than
$root.$iwindows.WindowInstanceName

You can refer to the current library using $clib. For example, to make the current library
private use
Do $clib.$isprivate.$assign(kTrue)
; is more generic than
Do $libs.MyLibrary.$isprivate.$assign(kTrue)

Do Command and Executing Methods


While you can use Calculate to change an object property or evaluate an expression, you
can use the Do command for all expressions that execute some notation. In this respect, the
Do command is the single-most powerful command in Omnis. You can use the Do
command to set the value of a property, or to run any standard or custom method. The Do
command has several variants which include
Do
sends a message to an object in your library, or assigns a value to an object property.
Normally you should execute the Do command in the context of the current object to
execute one of its methods or assign to one of its properties. There are a number of
common methods that you can use with the Do command including $open() to open an
instance of a class, $assign() to change an object property, and so on
Do inherited
executes the inherited method for the current method
Do default
runs the default processing for a custom method
Do redirect
redirects method execution to a custom method with the same name as the current
method contained elsewhere in your library
Do method
calls a method in the current class and returns a value
Do code method
runs a method in a code class and returns a value

75

Chapter 3Omnis Programming


Note that you can display a list of built-in methods for an object or object group by clicking
on the object in the Notation Inspector and opening the Property Manager. The methods for
an object are listed under the Methods tab in the Property Manager. See Omnis Studio Help
for a complete list of methods for all the objects in Omnis. The Show Runtime Properties
option in the Property Manager context menu lets you view properties that are normally
available in runtime only, that is, properties of an instance rather than a design class. When
runtime properties are visible in the Property Manager the methods for the instance are also
shown. You cannot set runtime properties or use methods shown in the Property Manager,
they are there as a convenient reference when you are writing code.

Do command
You can use the Do command in Omnis to do almost anything: execute some notation,
evaluate an expression, and so on. Specifically, you can use it to execute a method for an
object or assign a value to one of its properties. The Do command returns a value to
indicate whether the operation was successful or not, or for some methods a reference to the
object operated upon. This section shows you how you can use the Do command and
introduces some of the most useful methods.

Calling Private Methods


The callprivate() function allows you to call a private method within the current class or
instance and return a value. The syntax is:
callprivate(method[,parameters...] ;; calls the private method

The function can be called in client methods in the JavaScript Client.

$open() method
Using the Do command with the notation you can perform many operations that are
otherwise performed with a command. For example, the class types that you can open
contain an $open() method which you can execute using the Do command. For example,
you can open a window using
Do $windows.WINDOWNAME.$open(INSTANCENAME,kWindowCenter)
; opens a window in the center of the screen

The $open() method returns a reference to the instance created. For example
; Declare variable WindRef of type Item reference
Set reference WindRef to LIB1.$windows.WindowName
Do WindRef.$open('WindowInstance') Returns WindRef
; WindRef now contains a reference to the window instance
; $root.$iwindows.WindowInstance which you can use elsewhere, e.g.
Do WindRef.$forecolor.$assign(kBlue)
;; changes the instance

You can use a null value instead of an instance name; therefore CLASS.$open() would
force Omnis to use the class name as the instance name. Alternatively you can use an
asterisk in place of the instance name and Omnis assigns a unique name to the instance,

76

Methods
using the notation CLASSNAME_number. You can return the instance name in an item
reference variable and use the reference in subsequent code. For example
; Declare variable iMenuRef of type Item reference
Do $menus.MCUSTOMERS.$open('*') Returns iMenuRef
; iMenuRef now contains a reference to the menu instance, which
; will be something like $root.$imenus.MCUSTOMERS_23

You can close an instance using the $close() method. For example, the following method
opens a window instance, lets the user do something, and closes the instance
; initially WindRef contains a reference to the window class
Do WindRef.$open('WindowInstance') Returns WindRef
; let the user do something
Do WindRef.$close()

You can close the current window from inside the instance using
Do $cwind.$close()

Classes that contain the $open() methods also have the $openonce() method. This method
opens an instance if one does not already exist (excluding window menus, window toolbars,
and cascaded menus). In the case of a window, $openonce() brings the window to the top if
it is already open. $openonce() returns an item reference to the new or existing instance,
like $open().

$assign() method
You can change the properties of an object, including the properties of a library, class, or
field, using the Do command and the $assign() method. The syntax for the $assign() method
is NOTATION.PROPERTY.$assign(VALUE) where NOTATION is the notation for the object,
PROPERTY is the property of the object you want to change, and VALUE is a value depending
on the context of the object being changed. Usually you can use an Omnis constant to
represent a preset value, and for boolean properties, such as preferences, you can use kTrue
or kFalse to set the property as appropriate. For example
Do $clib.$prefs.$mouseevents.$assign(kTrue)
; turns on mouse events for the current library
Do $cclass.$closebox.$assign(kTrue)
; adds a close box to the current window class
Do $cfield.$textcolor.$assign(kGreen)
; makes the text in the current field green

$add() method
You can create a new object in your library using the $add() method. In the notation you are
really adding a new object to a particular group of objects. For example, to create a new
field on a window you need to add the object to the $objs group of objects for the window,
as follows

77

Chapter 3Omnis Programming


Do $cwind.$objs.$add(kPushbutton,iTop,iLeft,iHeight,iWidth)
; adds a pushbutton to the window with the
; specified size and position

When using $add(), you can return a reference to the new object in a return field of type
item reference. You can use the reference to change the properties of the new object. For
example
; Declare variable WindRef of type Item reference
Do $windows.$add('NewWindowName') Returns WindRef
; now use the reference to change the new window
Do WindRef.$style.$assign(kPalette)
Do WindRef.$title.$assign('Window title')
Do WindRef.$clickbehind.$assign(kTrue)
Do WindRef.$keepclicks.$assign(kFalse)
Do WindRef.$modelessdata.$assign(kTrue)
Do WindRef.$backcolor.$assign(kRed)
Do WindRef.$forecolor.$assign(kWhite)
Do WindRef.$backpattern.$assign(2)

$redraw() method
Note the $redraw() method is only relevant for fat client windows, not JavaScript Remote
Forms which redraw content automatically.
When you change an object or several objects on an open window using the Do command,
you often need to redraw the window. However if you change an object before $construct()
completes execution for the window instance, you dont need to redraw the window. You
can redraw an object, window, or all open windows using the $redraw() method. For
example
Do $cfield.$redraw()
; redraws the current field
Do $cwind.$redraw()
; redraws the current window
Do $root.$redraw()
; redraws all window instances

The $redraw() method has three parameters that allow you to specify the extent of the
redraw for window fields and/or background objects: the parameters are:
$redraw(bSetcontents,bRefresh,bBackObjects) where bSetcontents defaults to true,
bRefresh defaults to false, and bBackObjects defaults to false.
$root.$redraw(kTrue,kTrue)
; redraws the contents and refreshes all the field in all window
$root.$redraw(kFalse,kFalse,kTrue)
; redraws all background objects for all open windows

78

Methods

$sendall() method
You can send a message to all the items or objects in a group using the Do command and
the $sendall() method. For example, you can redraw all the objects in a group, you can
assign a value to all the members of an object group, or you can hide all the members of a
group using the $sendall() method and the appropriate message. The full syntax for the
method is:
$sendall({message|message,condition
[,bIgnoreUnrecognizedCustomAttribute=kFalse]})

where message is the message you want to send to all the objects and condition is a
calculation which the objects must satisfy to receive the message. For example
Do $iwindows.$sendall($ref.$objs.FIELDNAME.$redraw())
; redraws the specified field on all window instances
Do $cwind.$objs.$sendall($ref.$textcolor.$assign(kYellow))
; makes the text yellow for all the fields on the current window
Do $cwind.$objs.$sendall($ref.$visible.$assign(kFalse),$ref.$order<=5)
; hides the first five objects on the current window; useful
; for window subclasses if you want to hide inherited objects

The optional third argument bIgnoreUnrecognizedCustomAttribute causes $sendall() to


ignore unrecognized custom attribute errors, which would otherwise cause a runtime error
when the library preference $reportnotationerrors is kTrue. This argument defaults to kFalse
if omitted.

$sendallref ()method
When using $sendall(), you can use $ref to refer to the group member receiving the
message. However you can use $sendallref, which is an item reference to the item currently
receiving the message sent with $sendall (note that $sendallref is not supported in client
methods). Consider the case where a parameter passed to the message is evaluated by
calling another method, or a function implemented in an external component. In this case, if
you use $ref in the parameters passed to this other method or function, it will actually refer
to the item involved in making the call to evaluate the parameter. This is where
$sendallref() could be used, if you wish to pass some property of the group member
receiving the message to the other method or function.
For example:
Do $cinst.$bobjs.$sendall(
$ref.$text.$assign(
StringTable.$gettext(
$cclass.$bobjs.[$sendallref.$ident].$text)))

The example uses the text stored in the class as the row id in the string table, and assigns the
text stored in the string table to the background object. In the example, $sendallref.$ident
returns the ident of the background object receiving the message. If you were to use

79

Chapter 3Omnis Programming


$ref.$ident, the $ref would refer to the custom attribute representing the external component
function, and the call to $sendall would not have the desired effect.

$makelist() method
Quite often you need to build a list containing the names of all the objects in a group, and
you can do this using the makelist() method. For example
Do $clib.$classes.$makelist($ref.$name) Returns cLIST
; builds a list of all the classes in the current library and
; places the result in cLIST
Do $imenus.$makelist($ref.$name) Returns cLIST
; builds a list of all the currently installed menus

Do inherited
The Do inherited command runs an inherited method from a method in a subclass. For
example, if you have overridden an inherited $construct() method, you can use the Do
inherited command in the $construct() method of the subclass to execute the $construct()
method in its superclass.

Do default
You can use the Do default command in a custom method with the same name as a standard
built-in method to run the default processing for method. For example, you can use the Do
default command at the end of a custom $print() method behind a report object to execute
the default processing for the method after your code has executed.

Do redirect
You can use the Do redirect command in a custom method to redirect method execution to
another custom method with the same name that is contained in another object in your
library. You specify the notation for the instance or object you want execution to jump to.
Inheritance and custom methods are further discussed in the Object Oriented Programming
chapter.

Calculate Command and Evaluating


Expressions
This section describes how you use the Calculate command with an expression. It also
discusses using square bracket notation for strings. You should also see the later section on
error handling.
The Calculate command lets you assign a value to a variable calculated from an Omnis
expression. Expressions can consist of variables, field names, functions, notation strings,
operators, and constants. For example
Calculate var1 as var2+var3

in this case, var2+var3 is the expression.


80

Methods
Calculate var1 as con('Jon', 'McBride')

Here the expression uses the con() function which joins together, or concatenates, the two
strings Jon and McBride. You must enclose literal strings in quotes.
See the Omnis Studio Help for a complete list of functions. In expressions, functions appear
as the function name followed by parentheses enclosing the arguments to the function. The
function returns its result, substituting the result into the expression in place of the function
reference. Calling a function does not affect the flag.
The Omnis operators are shown below, in precedence order, that is, the order in which they
get evaluated by Omnis. Operators in the same section of the table are of equal precedence,
and are evaluated from left to right in an expression.
Parentheses
Unary minus
Multiplication
Division
Addition
Subtraction
Less than
Greater than
Equal to
Less than or equal to
Greater than or equal to
Not equal to
Logical AND
Logical OR

()
*
/
+
<
>
=
<=
>=
<>
&
|

When you combine expressions with operators, the order of expressions will often make a
difference in the interpretation of the expression; this is a consequence of the mathematical
properties of the operators such as subtraction and division. You can group expressions
using parentheses to ensure the intended result. For example
Calculate lv_Num as 100 * (2 + 7)

evaluates the expression in parentheses first, giving a value of 900. If you leave off the
parentheses, such as
Calculate lv_Num as 100 * 2 + 7

Omnis evaluates the * operator first, so it multiplies 100*2, then adds 7 for a value of 207.

Square Bracket Notation


You can use a special notation in strings to force Omnis to expand an expression into the
string. You do this by enclosing the expression in square brackets; Omnis evaluates the

81

Chapter 3Omnis Programming


expression when the string value is required. You can use this in all sorts of ways, including
the technique of adding a variable value to the text in the SQL or text buffer.
You can use square bracket notation wherever you can specify a single variable or field
name, including
command parameters, for example, OK message
OK message {Your current balance is [lv_curbalance]}

window or report fields; you can include values in text objects, such as
Your current balance is [lv_curbalance]

variable or field names within a Calculate command or text object


function parameters
Square bracket notation lets you refer to a value indirectly letting you code general
expressions that evaluate to different results based on the values of variables in the
expression; this is called indirection. For example, you can include a variable name
enclosed in square brackets in a text object to add the value to the text at runtime. However
in general, there is a significant performance penalty in using indirection.
If you need to use [ or ] in a string but do not want the contents evaluated, then use [[ and ]
to enclose the contentsdouble up the first or opening square bracket. This is useful when
you use square bracket notation with external languages that also use square brackets, such
as the VMS file system or DDE.

Type Conversion in Expressions


Omnis tries its best to figure out what to do with values of differing data types in
expressions. For example, adding a number and a string generally isn't possible, but if
Omnis can convert the string into a number, it will do so and perform the addition. Some
other examples are
; Declare local variable lDate of type Date D m Y
Calculate lDate as 1200
; 1200 is no. of days since 31st Dec 1900
Calculate lDate as 'Jun 5 93'
; conv string to date in format D m Y
OK message {Answer is [jst(lDate,'D:D M CY')]}
;; reformat date
Calculate lNum as lDate ;; sets lNum to 1200, the no. of days

Boolean values have a special range of possibilities.


YES, Y, or 1 indicate a true status
NO, N, or 0 indicate a false status
FALSE and TRUE are not valid values; Omnis converts them to empty.

82

Methods
; Declare local variable LBOOL of type Boolean
Calculate LBOOL as 1
;; is the same as...
Calculate LBOOL as 'Y' ;; or 'YES'
; the opposite is
Calculate LBOOL as 0 ;; or 'NO' or 'N'
OK message { The answer is [LBOOL] }
Calculate LBOOL as 'fui' ;; is the same as...
Calculate LBOOL as ''

You can convert any number to a string and any string that is a number in string form to a
number.
; Declare local variable lChar of type Character
; Declare local variable lNum of type Number floating dp
Calculate lChar as 100
OK Message { [lChar], [2 * lChar], and [con(lChar,'XYZ')] }
; Gives message output 100 200 and 100XYZ
Calculate lNum as lChar
Calculate lChar as lNum
OK Message { [lChar], [lNum * lChar], and [con(lChar,'ABC')] }
; Gives message output 100 10000 and 100ABC

Constants
You will often find situations in Omnis where you must assign a value that represents some
discrete object or preset choice. Omnis has a set of predefined constants you should use for
this kind of data. For example, a class type can be one of the following: code, file, menu,
report, schema, and so on. Each of these is represented by a constant: kCode, kFile, kMenu,
kReport, kSchema, respectively. You can get a list of constants from the Catalog; press
F9/Cmnd-9 to open the Catalog. You can use constants in your code, like this
Calculate obj1.$align as kRightJst
;; or use Do
Do obj1.$align.$assign(kRightJst)
; aligns the object obj1 to the right

Although you can use the numeric value of a constant, you should use the predefined string
value of a constant in your methods. In addition to ensuring you're using the right constant,
your code will be much more readable. Moreover, there is no guarantee that the numeric
value of a particular constant will not change in a future release of Omnis.

Calling Methods
You can execute another method in the current class using Do method, or call a method in a
code class using Do code method. These commands let you pass parameters to the called
method and return a value in a return field. For example, the following method named Setup
calls another method named Date and returns a value.

83

Chapter 3Omnis Programming


; Setup method
Do method Date (lNum,lDate+1) Returns lDate
OK Message {Date from return is [lDate]}
; Date method, the called method
; Declare Parameter var lpNum of type Number 0 dp
; Declare Parameter var lpDate of type Short Date 1980..2079
OK Message {Date from calling method is [lpDate], number is [lpNum]}
Quit method {lpDate + 12}

Note that when you call a code class method from within an instance the value of $cinst, the
current instance, does not change. Therefore you can execute code in the code class method
that refers to the current instance and it will work.
WARNING Omnis does not stop a method calling itself. You must be careful how the
method terminates: if it becomes an infinite loop, Omnis will exhaust its method stack.

Quitting Methods
You can use the Quit command, and its variants, to quit methods at various levels.
Quit method
quits the current method and returns a value to the calling method, if any
Quit event handler
quits an event handling method
Quit all methods
quits all the currently executing methods, but leaves Omnis running
Quit all if canceled
quits all methods if you press Cancel
Quit Omnis
exits your application and Omnis
You can also clear the method stack with the Clear method stack command, which does the
same thing as the debugger menu Stack>>Clear Method Stack; it removes all the methods
except for the current one. If you follow Clear method stack with Quit method, it has the
same effect as Quit all methods.
The Quit method command allows you to exit a method and return a value to the calling
method. For example:

84

Methods
;
;

Quit the method myMethod and return the flag


from the Yes/No message to the calling method

; the calling method


Do method myMethod Returns lReturnFlag
; method myMethod
Yes/No message {Continue ?}
Quit method #F

It is possible to call another method in the return value of a Quit method command, but this
can lead to unpredictable results, especially if the called method contains an Enter Data
command, e.g.
Quit method Returns iOtherObject.$doSomeThingThatContainsEnterData

Flow Control Commands


The Constructs... group contains many commands that let you control the execution and
program flow of your methods. If statements let you test a condition and branch
accordingly; loop commands iterate based on tests or sequences; the Comment command
lets you comment your code; and reversible blocks let you manipulate objects and values
and restore their initial values when the block terminates.
Several commands in this command group have starting and terminating commands (If and
End if, for example). You must use the correct terminating command, or you will get
unexpected results. If chromacoding is enabled, the beginning and terminating commands
for most branching and looping constructs are highlighted. You can enable chromacoding
using the View>>Show ChromaCoding menu option in the method editor.

Branching Commands
The If command lets you test the flag, a calculation, or a Cancel event. The Flag is an
Omnis variable with a True or False value which is altered by some commands to show an
operation succeeded, or by user input. The Else command lets you take an alternative action
when the If evaluates to false, Else if gives you a series of tests. You must use the End If
command to terminate all If statements.
A simple test of the flag looks like this:
If flag true
Do method Setup
End if

You can do a sequential checking of values using a calculation expression:

85

Chapter 3Omnis Programming


If CollCourse ='French'
Do method Languages
Else If CollCourse = Science
If CollSubCourse = Biology
Do method ScienceC1
Else
Do method ScienceC2
End If
Else
OK message {Course is not available.}
End If

While Loops
The While loop tests an expression at the beginning of a loop. The While command will not
run the code block at all if the expression is false immediately. You would use a While
command when you want to loop while an expression is true.
; Declare Count with initial value 1
While Count <= 10
OK message {Count is [Count]}
Calculate Count as Count + 1
End While

This loop will output 10 messages. If the condition was Count <= 1, it would run only
once.

Repeat Loops
A Repeat loop lets you iterate until an expression becomes true. Repeat loops always
execute at least once, that is, the test specified in the Until command is carried out at the
end of the loop, after the commands in the loop are executed, whereas While loops carry out
the test at the beginning of the loop.
; Declare Count of Integer type with initial value 1
Repeat
OK message {Count is [Count]}
Calculate Count as Count + 1
Until Count >= 10

This loop will output 9 messages.

86

Methods

For Loops
The For field value command lets you loop for some specific number of iterations, using a
specified variable as the counter. The following example builds a string of ASCII characters
from their codes using the functions con() and chr().
; Declare Count
Calculate cvar1 as ''
;; clear the string
For Count from 48 to 122 step 1
;; set the counter range
Calculate cvar1 as con(cvar1,chr(Count)) ;; add char to string
Do $cwind.$redraw()
End for

The For each line in list command loops through all the lines in the current list.
Set current list LIST1
For each line in list from 1 to LIST1.$linecount step 1
; process each line
End for

Switch/Case Statements
The Switch statement lets you check an expression against a series of values, taking a
different action in each case. You would use a Switch command when you have a series of
possible values and a different action to take for each value.
The following method uses a local variable lChar and tests for three possible values, A,
B, and C.
; Parameter pString(character 10)
;; receives the string
Calculate lChar as mid(pString, 1, 1)
;; takes the first char
Switch lChar
Case A
; Process for A
Case B
; Process for B
Case C
; Process for C
Default
; do default for all cases other than A, B, or C
End switch

It is a good idea to use the Switch command only for expressions in which you know all the
possible values. You should always have one Case statement for each possible value and a
Default statement that handles any other value(s).

87

Chapter 3Omnis Programming

Escaping from Loops


While a loop is executing you can break into it at any time using the break key combination
for your operating system: under Windows it is Ctrl-Break, under MacOS it is Cmndperiod, and under Unix it is Ctrl-C. Effectively, this keypress quits all methods. When
Omnis performs any repetitive task such as building a list, printing a report, or executing a
Repeat/While loop, it tests for this keypress periodically. For Repeat/While loops, Omnis
carries out the test at the end of each pass through the loop.
To create a more controlled exit for the finished library, you can turn off the end of loop test
and provide the user with a working message with a Cancel button. When the Cancel
button is visible on the screen, pressing the Escape key under Windows or Cmnd-period
under MacOS is the equivalent to clicking Cancel. For example
Disable cancel test at loops
;; disables default test for loops
Calculate Count as 1
Repeat
Working message (Cancel box) {Repeat loop...}
If canceled
Yes/No message {Do you want to escape?}
If flag true
Quit all methods
End If
End If
Calculate Count as Count+1
Until Count > 200

The If canceled command detects the Cancel event and quits the method. To turn on testing
for a break, you can use the Enable cancel test at loops command.
The Break to end of loop command lets you jump out of a loop without having to quit the
method, and the Until break provides an exit condition which you can fully control. For
example
Repeat
Working message (Cancel box) {Repeat loop...}
If canceled
Yes/No message {Are you sure you want to break out?}
If flag true
Break to end of loop
End If
End If
Until break
OK message {Loop has ended}

88

Methods
If you have not disabled the cancel test at loops, a Ctrl-Break/Cmnd-period/Ctrl-C
terminates all methods and does not execute the OK message. Having turned off the
automatic cancel test at loops, you can still cause a Quit all methods when canceled. For
example
Disable cancel test at loops
Calculate Count1 as 1
Calculate Count2 as 1
Repeat
Repeat
Working message (Cancel box) {Inner repeat loop}
Calculate Count2 as Count2 + 1
Until Count2 > 12
Calculate Count2 as 1
Working message (Cancel box) {Outer repeat loop...}
Quit all if canceled
Calculate Count1 as Count1 + 1
Until Count1 > 20

If the user selects Cancel in the outer loop, the method quits, but from the inner loop there is
no escape.

Optimizing Program Flow


Loops magnify a small problem into a large one dependent on the number of iterations at
runtime, and other program flow commands can use a lot of unnecessary time to get the
same result as a simpler command.
Here are some tips to help optimize your methods.
Use the For command instead of the equivalent While or Repeat commands. For has a fixed
iteration, while the other commands test conditions. By eliminating the expression
evaluation, you can save time in a long loop.
Use the Switch command instead of equivalent If/Else commands where possible. Arrange
both the Case commands within a Switch and the several If and Else if commands so that
the conditions that occur most frequently come first.
Use the Quit method command to break out of a method as early as possible after making a
decision to do so. This can be a tradeoff with readability for long methods because you have
multiple exits from the method; if falling through to the bottom of the method involves
several more checks, or even just scanning through a large block of code, you can
substantially improve performance by adding the Quit method higher up in the code.
Avoid using commands that dont actually execute within a loop. For example, dont put
comment lines inside the loop. You can also use Jump to start of loop to bypass the rest of
that iteration of the loop.

89

Chapter 3Omnis Programming


You can speed up a frequently called method by putting Optimize method at the start: refer
to Omnis Studio Help for details of this command.

Reversible Blocks
A reversible block is a set of commands enclosed by Begin reversible block and End
reversible block commands; a reversible block can appear anywhere in a method. Omnis
reverses the commands in a reversible block automatically, when the method containing the
reversible block ends, thus restoring the state of any variables and settings changed by the
commands in the reversible block.
; commands...
Begin reversible block
; commands...
End reversible block
; more commands...

Reversible blocks can be very useful for calculating a value for a variable to be used in the
method and then restoring the former value when the method has finished. Also you may
want to change a report name, search name, or whatever, knowing that the settings will
return automatically to their former values when the method ends.
The Omnis Help (press F1) indicates which commands are reversible.
Consider the following reversible block.
Begin reversible block
Disable menu line 5 {Menu1}
Set current list cList1
Define list {cvar5}
Build window list
Calculate lNum as 0
Open window instance Window2
End reversible block
; more commands...

When this method terminates:


1. Omnis closes window Window2
2. Omnis restores lNum to its original value
3. The definition of cList1 returns to its former definition
4. Omnis restores the former current list
5. Omnis enables line 5 of Menu1
At the end of the method, Omnis steps back through the block, reversing each command
starting with the last. If there is more than one reversible block in a method, Omnis reverses
90

Methods
the commands in each block, starting from the last reversible block. If you nest reversible
blocks, the commands in all the reversible blocks are treated as one block when they are
reversed, that is, Omnis steps backward through each nested reversible block reversing each
command line in turn. You cannot reverse any changes that the reversible block makes to
Omnis data files or server-based data unless you carefully structure the server transaction to
roll back as well.

Losing property values


Certain notation properties affect other properties when they are assigned, for example,
assigning $calculated to kFalse clears $text for the field. Therefore, if the $calculated
property is set within a reversible block, and the state of $calculated is reversed, the value in
the $text property is not reinstated. Such relationships between properties are not supported
by the reversible block mechanism. If you wish to maintain the value of a property that may
get cleared during notation execution, you should store the value in your own variable and
assign the value to the property at runtime.

Error Handling
When you enter a command, Omnis automatically checks its syntax. When a command is
executed in a method, you can get a runtime error, a processing error rather than a syntax
error. Fatal errors either display a message and stop method execution or open the
debugger at the offending command.
You can cause a fatal error to occur with the Signal error command, which takes an error
number and text as its argument. This lets you define your own errors, but still use the
standard Omnis error handler mechanism.
In addition, Omnis maintains two global system variables #ERRCODE and #ERRTEXT
that report error conditions and warnings to your methods. Fatal errors set #ERRCODE to a
positive number greater than 100,000, whereas warnings set it to a positive number less than
100,000.
You can trap the errors and warnings by adding a method to test for the various values of
#ERRCODE and control the way Omnis deals with them; this is called an error handler.
The command Load error handler takes the name of the method and an optional error code
range as its parameters:
Load error handler Code1/1 {Errors}
; warnings and errors will be passed to handler in code class

Once you install it, Omnis calls the error handler when an error occurs in the specified
range. Please refer to the Omnis Studio Help for a detailed description of the Load error
handler command and examples of its use.
There are several commands prefixed with SEA, which stands for Set error action. Using
these commands, you can tell Omnis what to do after an error:

91

Chapter 3Omnis Programming


SEA continue execution
continues method execution at the command following the command that signaled the
error; if the error handling routine has not altered them, #ERRCODE and #ERRTEXT
are available to the command
SEA report fatal error
if the debugger is available, it displays the offending command in the method window
and the error message in the debugger status line
SEA repeat command
repeats the command that caused the error.
Repeating a command should be done with care since it is easy to put Omnis into an endless
loop. If the error has a side effect, it may not be possible to repeat the command. If an Out
of memory condition occurs, it may be possible to clear some lists to free up enough
memory to repeat the command successfully.

Calculation Errors
The library preference $reportcalculationerrors (default is true) specifies whether or not
calculation errors are reported. When true, Omnis will report errors that occur when
evaluating calculations, such as divide by zero errors. The report message is sent to the trace
log, containing the error and code that caused the problem.
In addition, when executing calculations using Do and Calculate, Omnis enters the
debugger when the error occurs (provided debugging is allowed). This will not occur when
these commands execute in the Omnis web client.

Redrawing Objects
There are a number of commands that let you redraw a particular object or group of objects.
The Redraw command has the following variants.
Redraw field or window
redraws the specified field or window, or list of fields or windows; note this command
with refresh all instances of the window
Redraw lists
redraws all list fields on the current window or redraws all lists in your library
Redraw menus
redraws all the currently installed menus
Redraw toolbar
redraws the specified custom toolbar
You can use the $redraw() method to redraw a field or fields, a window or all windows, as
described earlier in this chapter.

92

Events

Refreshing window instances


You can use the $norefresh window instance property to control the refreshing of windows.
When set to kTrue screen updates are disabled and the window is not refreshed. You can
use this property to improve performance, for example when setting a large number of
exceptions for a complex grid. Setting the $norefresh property to kFalse will enable screen
refreshing.

Message Boxes
There are a number of message boxes you can use in your library to alert the user. The
commands for these messages are in the Message boxes... group. They include
OK message
displays a message in a box and waits for the user to click an OK button. For emphasis
you can add an info icon and sound the system bell. You can use square bracket
notation in the message text to display the current value of variables or fields. For
example, OK message {[sys(5)]} will display the users serial number. You can use the
kCr constant enclosed in square brackets to force a line break in the message, e.g. 'First
line[kCr]Second line'.
Yes/No message, and No/Yes message
displays a message in a box and waits for Yes or a No answer from the user. Either the
Yes or the No button is the default. You can use the kCr constant enclosed in square
brackets to force a line break in the message, e.g. 'First line[kCr]Second line'.
Prompt for input
displays a dialog prompting the user for input
Working message
displays a message while the computer is processing data or executing a method; with a
Cancel button the user can break into the processing with Ctrl-Break/Cmndperiod/Ctrl-C

Events
Events are reported in Omnis as event messages. These messages are sent to the event
handling methods as one or more event parameters. The first parameter of an event
message, pEventCode, contains an event code representing the event. Event messages may
contain a second or third parameter that tell you more about the event. For example, a click
on a list box will generate an evClick event plus a second parameter pRow telling you the
row clicked on. Note that all event codes are prefixed with the letters ev, and all event
parameters are prefixed with the letter p. You can use the event codes in your event
handling methods to detect specific events, and the event parameters to test the contents of
event messages.

93

Chapter 3Omnis Programming


When an event occurs the default action normally takes place. For example, when the user
presses the tab key to move to the next field on a data entry field, the default action is for
the cursor to leave the current field and enter the next field on the window, and normally
this is exactly what happens. However you could put a method behind the field that
performs any one of a number of alternative actions in response to the tab. That is, the event
handling method could use the tab to trigger a particular piece of code and then allow the
default action to occur, it could pass the event to somewhere else in your library, or it could
discard the event altogether and stop the default action from happening.

Event Handling Methods


You can write an event handling method for each field and object contained in window,
menu, toolbar, and report classes. The other class types do not generate events. You add the
event methods for window and report fields in the Field Methods for the class. For menu
classes you can add an event method to the Line Methods for a menu line, and for toolbar
classes you can enter an event method in the Tool Methods for each toolbar control.
Events for remote forms and web components are described in the Developing Web
Applications chapter in this manual.
Window fields, toolbar controls, and menu lines contain a default event handling method
called $event(), and report fields contain a default event handling method called $print(). If
you open the field methods for a window field, toolbar control, or menu line you will see an
$event() method, and for each report field you will see a $print() method for the object.
These are the default event handling methods for those objects.
To view the event handling method for a field or object

Show the design screen for the class

Right-click on the field, menu line or toolbar control

Choose Field Methods, Line Methods, or Tool Methods, as appropriate

The method editor opens showing the first method in the list for the field or object. If this is
not the $event() method, select it from the list to view it. Some event handlers will contain
code to handle a range of possible events in the object.
The event handling method for some types of field may be empty, because there is only one
possible event for the object. For example, the event handling method for a menu line is
empty since you can only select a menu line. Therefore any code you put in the $event()
method for a menu line runs automatically when you select the line.

94

Events
To enter the code for an event handling method

Assuming you have opened a default $event() method for a field, click on the next
command line after the On command

or, for an empty $event() method

Select the first line of the method

For example, you can open the event method for a pushbutton, that contains a single On
evClick command which will detect a click on the button.

Enter the code you want to run for that event

You could use the Do command and some notation in your event handling method, or you
can use the Do method command to run another method in the current class or instance, or
the Do code method command to run a method in a code class; in all cases, you can put
literally any code in an event handling method and it will run given the right event.

The On Command
You can use the On command to detect events in your event handling methods. Fields from
the Component Store may contain a default event handling method with one or more On
commands to detect different events. For example, an entry field contains the method
On evBefore
On evAfter

;; Event Parameters - pRow ( Itemreference )


;; Event Parameters - pClickedField,
pClickedWindow, pMenuLine,
pCommandNumber, pRow

These lines detect the events evBefore and evAfter, which are the event codes contained in
the message sent when the user enters or leaves the field, respectively. The in-line
comments indicate which event parameters Omnis supplies for that event. In most cases, the
event parameters are references containing values to do with the context of the event: the
field clicked on, the list row number, the menu line number, and so on.
When you select the On command in the method editor, the list of possible events changes
to reflect the events supported by the object to which $event belongs. You can also view
events divided into categories, by using the Events tab of the Catalog.
You can use the default event handling method for a field or add your own. The following
event handler for a data entry field detects an evBefore as the user enters the field and
performs a calculation changing the value of the field.
On evBefore
Calculate cDate as #D
Redraw {DateField}
Quit event handler

;; user tabs into date field


;; cDate is the dataname of the field
;; the current field

95

Chapter 3Omnis Programming


Code which is common to all events should be placed at the start of the event handling
method, before any On commands. You can use the On default command to handle any
events not covered by an earlier On command line. The general format is
; code which will run for all events
On evBefore
; code for evBefore events
On evAfter
; code for evAfter events
On default
; code for any other events

When you enter the On command in an event handling method, it displays a list of all the
available event codes in the command palette. You can click on the one you want, or you
can enter more than one event code for a single On command, for example On evClick,
evDoubleClick. On commands cannot be nested or contained in an If or loop construct.
When you have entered the On command line for a particular event and selected the next
command line, you can open the Catalog to view the event parameters for that event code.

Click on the line after an On evClick command line

Open the Catalog (F9/Cmnd-9)

Click on Event Parameters under the Variables tab

For example, an On evClick command displays the parameters pEventCode and pRow in
the Catalog. You can use these event parameters in your event handling methods to test the
event message. A click on a list box generates an evClick event message containing a
reference to the row clicked on, held in the pRow event parameter. You can test the value of
pRow in your code
On evClick
;; method behind a list box
If pRow=1
;; if row 1 was clicked on
; Do this...
End If
If pRow=2
;; if row 2 was clicked on
; Do that...
End If

96

Events
All events return the parameter pEventCode, which you can also use in your event handling
methods.
On evAfter,evBefore
;; method behind field
; Do this code for both events
If pEventCode=evAfter
; Do this for evAfter events only
End If
If pEventCode=evBefore
; Do this for evBefore events only
End If

The parameters for the current event are returned by the sys(86) function, which you can use
while debugging or monitoring which events are handled by which methods. For example,
you could use the Send to trace log command and the functions sys(85) and sys(86), to
report the current method and events, in the $event() method for a field
; $event() method for field 10 on the window
Send to trace log {[sys(85)] - [sys(86)]}
; sends the following to the trace log when you tab out of the field
WindowName/10/$event - evAfter,evTab
WindowName/10/$event - evTab

You can use any of the parameters reported for an event in your event handling methods.
However, if you enter an event parameter not associated with the current event, the
parameter will be null and lead to a runtime error.

Mouse Events
Mouse events allow you to detect user mouse clicks inside fields and the background of a
window. Mouse and right- mouse button events are generated only if the $mouseevents and
$rmouseevents library preferences are enabled. Under Mac OS, right-mouse events are
generated when you hold down the Ctrl key and click the mouse.
evMouseDouble and evRMouseDouble
the mouse, or right-mouse button is double-clicked in a field or window
evMouseDown and evRMouseDown
evMouseUp and evRMouseUp
the mouse, or right-mouse button is held down in a field or window, or the mouse
button is released; for the mouse-down events you can detect the position of the mouse,
se below
evMouseEnter and evMouseLeave
the mouse pointer enters, or leaves a field

97

Chapter 3Omnis Programming


evDrag
the mouse is held down in a field and a drag operation is about to start; the parameters
report the type and value of the data
evCanDrop
whether the field or window containing the mouse can accept a drop; the parameters
reference the object being dropped, the type and value of the data
evWillDrop
the mouse is released at the end of a drag operation. The parameters reference the
object being dropped, the type and value of the data
evDrop
the mouse is released over the destination field or window at the end of a drag
operation. The parameters reference the object being dropped, the type and value of the
data
For the evMouseDown, evMouseUp, evRMouseDown and evRMouseUp events you can
return the position of the mouse as the X-Y coordinates relative to the window background
or field.
pMouseX
Mouse x coordinate
pMouseY
Mouse y coordinate
pMouseHwnd
window identifier of the hwnd receiving the mouse event; the mouse coordinate
parameters are relative to this hwnd
The coordinate origin is the top-left of the hwnd.

The Quit event handler Command


If you want to discard or pass an event you can use the Quit event handler command to
terminate an On construct. A field event handling method might have the following
structure.
; general code for all events
On evBefore
; code for evBefore events
On evAfter
; code for evAfter events
On evClick,evDoubleClick
; code for click events
Quit event handler (pass event)
On default
; code for any other events

98

Events
The Quit event handler command has two options
Discard event
for some events you can discard the event and stop the default action taking place
Pass to other handlers
passes the event to the next handler in the chain

Discarding Events
In certain circumstances you might want to detect particular events and discard them in
order to stop the default action from occurring. You can discard or throw away events using
the Quit event handler command with the Discard event option enabled. Note however, you
cannot discard some events or stop the default action from taking place since the event has
already occurred by the time it is detected by an event handling method. In this case, a Quit
event handler (Discard event) has no effect for some events.
Being able to discard an event is useful when you want to validate what the user has entered
in a field and stop the cursor leaving the field if the data is invalid. The following method
displays an appropriate message and stays in the field if the user does not enter the data in
the correct format.
On evAfter
;; as user leaves the field
If len(CustCode <> 6)
;; check a value has been entered
If len(CustCode = 0) ;; field left blank
OK message {You must enter a customer code}
Else
;; wrong length code entered
OK message {The customer code must have 6 digits}
End If
Quit event handler (Discard event) ;; stay in the field
End If

You can also handle or discard events using the Quit method command with a return value
of kHandleEvent or kDiscardEvent, as appropriate.

Window Events
So far the discussion has focused on field events, which you would normally handle in the
field using an event handling method. However you can enter methods to handle events that
occur in your window as well. Like fields, the event handling method for a window class is
called $event(), and you enter this method in the Class Methods for the window class.
Window classes do not contain an $event() method by default, but you can insert a method
with this name. You enter the code for a window $event() method in exactly the same as for
fields using the On command to detect events in your window.
Window events affect the window only and not individual fields. They include clicks on the
window background, bringing the window to the front or sending it to the back, moving it,

99

Chapter 3Omnis Programming


sizing it, minimizing or maximizing the window, or closing it. For example, when you click
on a windows close box, the evCloseBox and evClose events are generated in the window
indicating that the close box has been clicked and the window has been closed. You could
enter an $event() method for the window to detect these events and act accordingly.
The following window $event() method detects a click on a window behind the current
window, and discards the click if the user is inserting or editing data.
On evWindowClick
;; user has clicked on a window behind
If cInserting | cEditing
;; vars to detect current mode
OK message {You cannot switch windows while entering data}
Quit event handler (Discard event) ;; keep window on top
End If
Quit event handler

The following window $event() method checks for events occurring in the window and runs
the appropriate methods elsewhere in the class. Note you cannot trap an evResize and
discard it since the resizing has already occurred, but you can reverse the resizing by setting
the size of the open window back to the size stored in the class.
On evToTop
Do method Activate
Quit event handler
On evWindowClick
Do method Deactivate
Quit event handler
On evClose
Do method Close
Quit event handler
On evResized
Do $cwind.$width.$assign($cclass.$width)
Do $cwind.$height.$assign($cclass.$height)
Quit event handler (Discard event)

Window Event Handling (OS X)


Under Mac OS X, whenever the end-user clicks on a window title bar (or a button on the
window title bar) the evWindowClick event is generated. The event parameter
pStayingBehind is true if the window receiving the click will not come to the front as a
result of the click (this event can only ever be true on OS X). For example, when the user
clicks on the zoom box of a window that is not on top, the window will zoom or restore, but
will not come to the top.

100

Events

Key events
You can detect which key or key combination is pressed by trapping the evKey event. The
evKey event is sent to the target field when a key is pressed, and has three parameters as
follows:
pEventCode
The event code
pKey
The key pressed
pSystemKey
The system key pressed represented by a code, as follows:
0

Letter/Number

26

End

1...12

F1...F12

27

Tab

17

Up Arrow

28

Return

18

Down Arrow

29

Enter

19

Left Arrow

30

Backspace

20

Right Arrow

32

Esc

21

Page Up

34

Delete

22

Page Down

35

Insert

25

Home

53

Context Menu

Control Methods and Passing Events


As already described, you handle events for fields using an event handling method
contained in the field, but you can add a further level of control over field events by adding
a method called $control() to your window. This method is called a window control method.
To allow this method to handle events you must pass events to it from the field event
handling methods. You do this by including in your field event handler the Quit event
handler command with the Pass to next handler option enabled.
As a further level of control, you can add a $control() method to your tasks. This method is
called a task control method. Events are passed to the task control method from the window
control method contained in the window belonging to the task. Therefore, an event may be
generated in the field, passed to the window control method, and then passed to the task
control method.
Window events that are handled in the $event() method for a window can be passed to the
task $control() method as well.

101

Chapter 3Omnis Programming


At each level an event handling method can discard the event or pass it on to the next event
handler. At the task level, the highest level of control, the event can be processed and the
default action takes place, or the event can be discarded and no further action occurs.
The Omnis event processing mechanism gives you absolute control over what is going on in
your application, but it also means you need to design your event handling methods with
care. It is important not to pass on an event to higher levels unnecessarily and to keep
control methods short, to limit the time spent processing each event.
In the following example, the $control() method is contained in an Omnis data entry
window. It sets the main file for the window when it is opened or comes to the top, and does
not let the user close the window if Omnis is in data entry mode.
On evToTop
; window comes to the top or is opened
Set main file {FCUSTOMERS}
Quit event handler
On evClose
If cInserting | cEditing
;; vars to detect current mode
; User closes window when in enter data mode
OK message {You can't close in enter data mode}
Quit event handler (Discard event)
End If

Event Processing and Enter Data Mode


Normally, the default processing for an event takes place when all the event handler
methods dealing with the event have finished executing. It is not possible to have active
unprocessed events when waiting for user input so the default processing is carried out for
any active events after an Enter data command has been executed or at a debugger break.
Therefore if required, you can use the Process event and continue command to override the
default behavior and force events to be processed allowing an event handling method to
continue.
The Process event and continue (Discard event) option lets you discard the active event.
For example, in an event handler for evOK the following code would cause the OK event to
be thrown away before the subsequent enter data starts.
On evOK
Process event and continue (Discard event)
Open window instance {window2}
Enter data

102

Events

Container Fields and Events


Container fields are fields that contain other fields; examples of container fields include
subwindows, tab panes, page panes, scroll boxes, and complex grid fields. The logic for
handling and passing events within a container field is the same as for simple fields, it just
has more levels of control.
For the purposes of event handling, you can regard the container field as both a field on the
parent window, and a window since it contains other fields. In this respect, a container field
can have an $event() method that handles events for the container field itself, and a
$control() method that handles events passed to it from the individual fields inside the
container field. Each field in the container field has a $event() method to handle its own
events. If the control method for your container field allows it, events are passed to the
parent window control method, which in turn can be passed onto the task control method or
discarded as appropriate.
You can nest container fields such as subwindows and tab panes, but nested container fields
do not pass events.

Queuing Events
Some user actions generate a single event which is handled as it occurs by your event
handling methods. The event may be dealt with completely in the field or it may be passed
up the event chain as required. However some user actions generate a whole series of
events, one after another. These events are placed in an event queue. Each event is handled
by your event handling methods strictly in turn on a first-in, first-out basis. For example,
when the user tabs from one field to another the current field is sent an evAfter and then an
evTab event, then the new field is sent an evBefore event: all these events are placed in the
event queue in response to a single user action, the tab. Similarly when you close a window,
the current field is sent an evAfter, the window is sent an evCloseBox event, then it is sent
an evClose event. Each one of these events is sent to the appropriate object and is handled
by your event handling methods before the next event in the queue is handled.
In addition to events generated by user actions, you can append an event to the event queue
using the Queue commands in the Events... group.

103

Chapter 3Omnis Programming


Queue
Queue
Queue
Queue
Queue
Queue
Queue
Queue
Queue
Queue
Queue

bring to top
close
cancel
set current field
click
double-click
keyboard event
OK
scroll (Left|Right|Up|Down)
tab
quit

These commands let you simulate user actions such as key presses and clicks on buttons or
windows. For example, the Queue bring to top {WINDOWNAME} command brings the
specified window instance to the top and simulates a user clicking behind the current
window. Events generated by these commands are handled after those that are currently
queued. You can queue several events in succession.

Using Tasks
Omnis contains two environments, a design mode and a runtime mode. In design mode, you
can create and store classes in your library. In runtime mode, various objects or instances
are created as you run your application. You can group and control the runtime objects in
your application by opening or instantiating them in a task. You can manipulate whole
groups of instances by manipulating their task, rather than having to deal with each separate
instance. You define a task in your library as a task class.
Task classes can contain variables and methods, and you can define custom properties and
methods for a task class as well. When you open a task you create an instance of that task
class. The task instance is unique in Omnis in that it can contain other instances including
window, report, toolbar, and menu instances. Task instances cannot contain other tasks.
When you open an instance from within a task it belongs to or is owned by that task.
By opening and closing different tasks, or by switching from one task instance to another,
you can control whole groups of objects. Omnis provides certain default actions which
happen as the task context switches. You define exactly what happens in the task by
creating methods in the task class. For example, in the task you can specify which windows
are opened and which menus are installed using commands or the notation.
Each library contains a group of task classes called $tasks, and Omnis has a group
containing all open task instances called $root.$itasks in the order that they were opened.
For web applications, Omnis provides remote tasks to handle client connections and remote
form instances. These are described later in this chapter.

104

Using Tasks

Default and Startup Tasks


When Omnis opens, it creates a task instance for the IDE to run in. This task is called the
default task, and is represented in the notation as $root.$defaulttask. This task instance
contains all the IDE objects such as the Browser, Catalog, Property Manager, and so on.
When you create a new library, it contains a task class called Startup_Task by default.
When you open a library, an instance of the startup task is created automatically. From
thereon all instances opened in the library are owned by the startup task. You can delete the
startup task, or you can create other tasks for your application components to run in.
$defaulttask instance
B ro w s e r
C a ta lo g

Startup task instance


A b o u tW in d o w
in s ta n c e

M a in M e n u
in s ta n c e

Mytask1 instance

W in d o w
in s ta n c e X
M enu
in s ta n c e A

It is not essential to add tasks to your library, your library will safely execute in the startup
task, or the default task along with the IDE objects.
The startup task instance has the same name as your library. For a simple application, the
startup task will probably be all you need, with all the other class instances belonging to it.
The startup task remains open for as long as the library is open, but you can close it at any
time using a command or the notation. You can change the name of the task to be opened on
startup by setting the library preference $startuptaskname; for all new libraries this is set to
Startup_Task by default.
If you have an application that spans multiple libraries, often only the library used to start
the application will have a startup task. If a library is opened using the Open library
105

Chapter 3Omnis Programming


command with the option Do not open startup task, the startup task is not instantiated. In
design mode, you can stop a librarys startup task from running if you hold down the
Alt/Option key as you open your library.

Handling application focus events


You can control application focus events generated by the Operating System using the task
methods $omnistofront() and $omnistoback(). These methods can be added to the Startup
task in your library.
$omnistofront()
called when Omnis is brought to the front by the Operating System as a result of a user
action such as a mouse click or alt-tab key combination. On Mac OS X, an extra
boolean parameter is passed to $omnistofront(). If the value of this parameter is kTrue,
the user has clicked on the Omnis Icon in the Dock. If a user clicks on the Omnis Dock
Icon, $omnistofront() will be called twice. The first call will be generated as a result of
an OS AppActivated event and the parameter value will be kFalse. The second call will
be generated as a result of the Dock click and the parameter value will be kTrue.
$omnistoback()
called when Omnis is sent to the back by the Operating System as a result of a user
action such as a mouse click or alt-tab key combination. For $omnistoback() you
should only use Omnis code which produces a non-visual result. Attempting to open
windows, and so on, while Omnis is losing the application focus may have undesirable
affects and is not supported.

Creating Task Classes


This section describes how you create a task class from the Browser.
To create a task class

Open your library and select it in the Browser

Click on New Class and then the Task option

Name the new task

Double-click on the task class to modify it

You modify a task class in the method editor. You can place in the $construct() method any
code that you want to run when the task is opened. For the Startup_Task, the $construct()
method is executed when you open your library. You can add any other custom properties
and methods to the task, as well as any type of variable.

106

Using Tasks

Opening Tasks
Apart from the startup task instance, which is opened automatically when you open your
library, you can open a task using the Open task instance command or the $open() method.
Any parameters you supply with the command are sent to the tasks $construct() method.
Open task instance MyTask/TaskInstance2 (p1,p2,...)
; opens the task, assigns an instance name, and sends parameters

Alternatively you can open a task instance using the $open() method.
Do MyTask.$open(TaskInstance2,p1,p2,...) Returns iTaskRef
; does the same as above & returns a reference to the task instance

Current and Active Tasks


Omnis keeps references to two different tasks, the active task and the current task, to keep
track of the tasks that own the topmost instance or GUI object and the currently executing
method. The active task is the task that owns the topmost open window, installed menu, or
toolbar currently in use. The current task is the task that owns the currently executing
method.
A task context switch occurs when Omnis changes the current or active tasks. As Omnis
runs your library, the current and active tasks may point to different task instances
depending on the users actions.

The Active Task


The active task is affected by the user, and is typically the task containing the topmost open
window. When an instance belonging to another task is selected, Omnis performs a task
context switch. As part of the context switch, messages are sent to both tasks. The active
task gets sent a $deactivate() message, and the new active task is sent an $activate()
message.
When the active task changes, you can use the $activate() and $deactivate() messages to
perform other relevant actions such as hiding other windows, installing menus, and any
other requirements your application has.
In order for Omnis to perform an automatic task context switch when the user selects an
instance belonging to another task, the tasks $autoactivate property must be set to kTrue.
Omnis can install and remove menus and toolbars automatically during task context
switches. Menu and toolbar instances each have a $local property that you can set. When set
to true, the menu or toolbar instance is made local to the task that owns it. When a task
context switch occurs, local menus for the previously active task will be removed from the
menu bar, and any local menus instances owned by the new active task will be installed.
Toolbars behave similarly. If the tasks use different docking areas, Omnis will not hide the
docking areas, only the toolbars.

107

Chapter 3Omnis Programming


You can change the active task using the notation, rather than waiting for the user to initiate
a task context switch. To do this, you can set the property $root.$activetask to a different
task instance name to switch tasks.

The Current Task


The current task is under the control of Omnis itself, and is the task instance which contains
the currently executing method. When a custom attribute or event is sent to an instance, the
current task is switched to the task which owns the instance, and when control returns from
that attribute or event, the previous task is restored.
When the current task changes, messages are sent to both tasks. The current task is sent a
$suspend() message, and the new current task gets a $resume() message. If the new current
task is being instantiated for the first time, it gets a $construct() message rather than the
$resume().
In order to avoid endless recursion a task does not get suspend or resume messages during
the execution of a suspend or resume method.
Since $suspend() and $resume() are likely to be called frequently, it is important that the
code for them should be kept as short and efficient as possible and should not:
alter the user interface
open or close an instance
switch tasks
You can find out the name of the current task using the notation $ctask().$name, and the
task that owns the instance by using InstanceName.$task().$name.

Closing Tasks
You can close a task instance using the Close task command or the $close() method. When
you close a library all its task instances are closed, and when you quit Omnis the default
task is closed and all instances belonging to the default task are closed.
When you close a task, all instances belonging to that task are closed or destructed
providing they can be closed. When instances are closed, a message is sent to the instance
asking it to confirm whether or not it can be closed. If the instance returns a false message,
Omnis will not close that instance. For tasks, each instance belonging to the task is sent the
message, and then the task itself is sent the message. If any of the instances belonging to the
task cannot be closed, none of the instances nor the task instance are closed.

Task Variables
Task classes can contain both class and instance variables of any standard Omnis data type.
Tasks can also contain task variables, which are accessible to any instance owned by the

108

Using Tasks
task. As with other variables, you create task variables in the variable pane of the method
editor.
When two or more types of variable use the same variable name (this is not recommeded), a
reference to that variable may be ambiguous. In this situation, Omnis uses the variable with
the smallest scope automatically. All other variable scopes have precedence over task
variables.
When a method in a code class is called from another class or instance using the Do code
method command, the current task continues to point to the calling method. This allows
methods in a code class to have access to the task variables from the calling method.

The Design Task


In order for task variables to be available to you for use in design mode, you must establish
a connection between a class and the task whose variables you want to access. You do this
by setting the design task ($designtaskname property) for the class. The design task
determines which task variables are available to the class: if no design task has been set, the
method editor does not let you declare or see any task variables.
Setting the design task for a class doesnt guarantee that the task will be available in runtime
when you open your class, nor will Omnis automatically create an instance of the task. The
design task is simply a way to give you access to a set of task variables while you create the
classes in your library.
You can also access task variables without setting a design task by referring to the variable
as $ctask.variablename. This assumes that the variable will always belong to a task and can
therefore default to the current task.
If you attempt to access a task variable in an instance, and that variable is not available in
the task, a runtime error of Unrecognized task variable will be generated, and the variable
will have a NULL value.
If you rename a task variable, any references to it are not renamed. Also if one with that
name ceases to exist, references to it which were entered as VariableName are shown in
design mode as $ctask.VariableName. Similarly, if some code containing a task variable is
pasted into a different class, any task variables used by that code are not copied into the
destination class.

Private Instances
Normally an instance is visible to other tasks and you can reference it using the notation
from anywhere in your library. However you can override this default behavior by making
an instance private to the task that owns it. You can do this by setting the instances
$isprivate property to kTrue.
When you make an instance private, you cannot destruct it, make references to it, or even
see it unless you are within the task that owns it. A task can even be private to itself, so it
can be closed only when it is the current task. If access to a private instance is required from
109

Chapter 3Omnis Programming


outside of the task, an item reference can be set to the instance, and the item reference can
be passed outside of the task. Once this has occurred, the item reference can be used to
manipulate the instance.
The $root object has a series of object groups, one for each instance type, that are
represented in the notation as $iwindows, $imenus, $itoolbars, $ireports, $itasks. Each of
these object groups displays all public instances, as well as instances which are private to
the current task. As the current task changes, the contents of these groups may change to
reflect the private instances present in your library.

Private Libraries
Libraries can be private to a task, and both the library and its classes are visible only to that
task.
The group of open libraries, $libs, contains a private library only when the task which owns
that library is the active task. The Browser does not display classes from a private library.
Standard entry points to the debugger such as shift-click on a menu line do not enter the
debugger if the menu belongs to a private library.
As with private instances, if an item reference to any object within a private library is
passed to an object outside the library, it is able to access the library using notation.
You can make a library private by setting its $isprivate property to true. This is normally
done immediately after opening the library, but can be done at anytime as long as the task
which owns the library is the active task. Libraries also have the $alwaysprivate property,
which, if set, means they are always and immediately private to their startup task.
Private libraries have an additional property, $nodebug, which keeps the debugger from
being entered for any reason when code from that library is executing, including errors,
breakpoints, and the stop key. Code from a private library with $nodebug set does not
appear in the stack menu or the trace log.
When a task is closed, it closes all its private libraries unless they cannot be closed. This
can occur if, for example, the library has instances belonging to other tasks. If a private
library cannot be closed, it will become non-private.

110

Using Tasks

Multiple Tasks
When designing an application, you might want to partition your library by creating
modules containing all of the windows, reports and methods of like functionality. Each
module can have its own menus and toolbars. An example containing such modules might
be an accounting package, with General Ledger, Accounts Payable and Accounts
Receivable modules.
In a totally modal application, where the user switches between modules, it is easy to ensure
that the user sees the correct menus and tools for the current module. In a modeless, multiwindow environment, controlling this can sometimes be difficult. Tasks automate the
process of creating modular applications by providing all the management of menus and
tools for you.
Consider the following example in which a single library is running three tasks: the
Startup_Task and two user tasks Task1 and Task2. The startup task, which opens
automatically when the library opens, contains an About window. The other two tasks each
contain a window, a menu, and a toolbar. When the user selects a window from either Task1
or Task2, you may want Omnis to display the correct tools and menus for that window
automatically.

About window

Menu 1
Toolbar 1

Menu 2
Toolbar 2

Window 1
Startup_Task

Window 2
Task1

Task2

When the library opens, the startup task opens and displays the About window and then
opens the other tasks, each of which opens its window and installs its menu and toolbar. The
startup task can close itself once the About window is closed if its no longer needed.
To open the two tasks, you should execute the following in the $construct() method of the
startup task
Open window instance AboutWindow
Open task instance MyTaskClass1/Task1
Open task instance MyTaskClass2/Task2
Close task instance LibraryName ;; close Startup_Task instance

Every task has a property $autoactivate, that allows the task to take control whenever the
user tries to bring a window it owns to the front. If the property is set to false, the window
wont come to the front. To activate each task automatically, you need to execute the
following in the $construct() of each task
Do $ctask.$autoactivate.$assign(kTrue)

111

Chapter 3Omnis Programming


To ensure that your menus and toolbars show and hide appropriately as the tasks change,
you need to set the $local property for each class. By making each menu and toolbar local
to the task that owns it, Omnis hides and shows them automatically as the task context
changes.
In the $construct() for a task, you can install your menu and toolbar, and set their $local
property. For example
; $construct() for task1...
Do $menus.MyMenuClass1.$open(Menu1) Returns iMenuRef
Do iMenuRef.$local.$assign(kTrue)
Do $toolbars.MyToolbarClass1.$open(Toolbar1) Returns iToolRef
Do iToolRef.$local.$assign(kTrue)
Do $windows.MyWindowClass1.$open(Window1) Returns iWinRef

You can do the same for the other task.


; $construct() for task2...
Do $menus.MyMenuClass2.$open(Menu1) Returns iMenuRef
Do iMenuRef.$local.$assign(kTrue)
Do $toolbars.MyToolbarClass2.$open(Toolbar1) Returns iToolRef
Do iToolRef.$local.$assign(kTrue)
Do $windows.MyWindowClass2.$open(Window1) Returns iWinRef

This functionality will change menus and toolbars as you switch from one window to the
other.

Mac OS X Preferences
The Mac OS X application menu has a Preferences item. You can arrange for Omnis to call
a method in a task, when the user selects this menu item. To do this, define a method called
$prefs in your task. When the user selects Preferences from the application menu, Omnis
calls the $prefs method.
If more than one task defines $prefs, Omnis installs a hierarchical menu on the Preferences
menu item. Each task has an item in the hierarchical menu. In this case, each task must also
contain a method called $prefsmenutext. This method must return the text to display for the
tasks item in the hierarchical menu, for example
Quit Method My Library

112

External Component Notation

External Component Notation


The $components group under $root contains all the installed external components available
in your XCOMP folder. You can view the contents of the $components group using the
Notation Inspector.
Note that you manipulate an external component via its custom field properties, as shown
below, not via the $root.$components...$compprops or $compmethods groups for the
control. The groups under $root.$components is simply a convenient way of viewing the
contents and functions of any external library or control.
The $components group has the standard group properties and methods, including $add()
and $remove(), and you can list the components using the $makelist() method.
; declare variable cCompList of type List
Do $root.$components.$makelist($ref.$name) Returns cCompList

You can drag a reference to any of the components from the Notation Inspector to your
code, in the same way as other built-in objects. You can click on a component library in the
Notation Inspector and view its properties in the Property Manager. Each component library
has the following properties
$name
the name of the component which must be unique
$pathname
the name and path of the external library file; this will vary across different platforms
$functionname
the name of the external function
$controlhandler
Boolean that indicates whether the external is a control handler, for example, an
ActiveX is a control handler
$constprefix
String used as a prefix for all constants within the external
$flags
indicates the external flags, for example, whether it is loaded
$usage
Current number of controls that are using this external
$version
the version information
You can view the contents of an external library in the Notation Inspector. Each component
library has a group called $controls containing all the controls in the library. Some libraries
may contain only one control, for example, the Slider Component Library contains the
113

Chapter 3Omnis Programming


Slider Control only. A control contains its own events, functions (or methods), and
properties in their own respective groups, as follows
$compevents
group of events for the control
$comprops
group of properties for the control
$compmethods
group of methods for the control
In the notation you treat an external component property or function as you would a
standard built-in property or method, that is, you can use property and method names in the
notation to manipulate and send messages to an external component field. Note that
property and method names should include a dollar sign when you use them in the notation.
Do $cwind.$objs.ClockField.$facecolor.$assign(kBlue)
; assigns a color to the face of a clock component
; using the $facecolor property
Do $cwind.$objs.QTfield.$Play()
; executes the $Play() function for a QuickTime component

In general, the properties of an external component are unique to the object and their names
will not clash with standard Omnis field properties. However when an external component
property has the same name as an Omnis property, you must access the external property
using a double colon (::) before its name. For example, the Icon Field control has the
property $backcolor which you must refer to using
Do $cinst.$objs.iconfield.$::backcolor.$assign(kRed)
; would not work without the ::

At runtime you can add an external component to an open window using the $add() method.
You need to specify the kComponent object type, external library name, external control
name, and the position of the field. For example, the following method adds the Marquee
Control to the current window instance, positions the new object, and sets some of its
properties
; declare local variable Objref of type item reference
Do $cinst.$objs.$add(kComponent,'Marquee Library','Marquee
Control',0,0,15,100) Returns Objref
Do Objref.$edgefloat.$assign(kEFposnStatusBar)
; repositions the object at the bottom of your window
Do Objref.$message.$assign('I hope you can read quickly!')
Do Objref.$steps.$assign(20)
;; number of pixels to step
Do Objref.$speed.$assign(20)
;; lower number is faster
Do Objref.$::textcolor.$assign(kBlue)
;; note :: notation
Do Objref.$::backcolor.$assign(kRed)

114

External Component Notation

Version Notation
All external components have the $version property. To get the version of an external
component you must access it via the $root.$components group, not the external component
field on a window or report. For example
Do $root.$components.Marquee Library.$version Returns lvXversion
; returns 1.2 for example

If you have created any external components of your own to run under Omnis Studio
version 1.x, you must recompile them for Omnis Studio 2.0.

Java Beans
The Java Bean external component has commands that let you control it in a Runtime
Omnis. Note the Java Beans external is available under Windows only.
You request a command using the $cmd() method as follows:
$root.$components.JavaBean.$cmd(parameter list)

The parameters can be:


Parameter list

Command

"GetPaths", List

Populates the specified single column list with the Java Bean
search paths; no return value

"AddPath", NewPath

Adds the specified path to the Java Bean search paths; returns
true for success, or if the path is already present in the search
paths

"DeletePath", DelPath

Deletes the specified path from the Java Bean search paths;
returns true for success

"EnumBeans"

Enumerates Java Beans; returns the number of Beans found

"StartVM"

Starts the Java virtual machine (to test if Java is installed);


returns a string containing an error, or an empty string to indicate
success

"SetupDialog".

Opens the Java Bean component setup dialog

"RequestPath"

Opens the Prompt for Java Bean Path dialog; returns a string
containing the new path; empty if none selected

115

Chapter 3Omnis Programming

Debugging errors in the OCX handler


If you experience problems while using an Omnis component due to errors in the OCX
handler (OCXHNDLR) you should report this problem to Omnis Support. The problem is
usually caused by a faulty External DLL, but it may be difficult to detect which one is
causing the problem.
To diagnose the problem, create a text file called OCXHNDLR.LOG and place it in the
XCOMP folder. This file will log all the activity in the OCX handler during the lifetime of
the Omnis session, including the load status of each external DLL that Omnis attempts to
load.
If you contact Omnis Support, please include the OCXHNDLR.LOG file so we can
diagnose the problem. Ensure that you delete the file when logging is no longer required, as
performance will be affected.

116

External Component Notation

Chapter 4Debugging
Methods
You add variables and methods to the objects in your library using the Method Editor. You
can edit and debug the methods in your library using the Omnis debugger which is an
integral part of the method editor. Using the method editor, you can:
Insert and Edit methods
Run and step through methods
Set breakpoints
Trace the execution of method lines and field values
View and alter fields and variables
Inspect the method stack
Debug your code using the debugger commands
The Omnis debugger provides several tools to help you monitor the execution of a method,
including the ability to create watch variables, interrogate and edit the contents of variables
during execution, and place a variety of breakpoint conditions, which when met will
interrupt execution.
The debugger operations are controlled from the Debug and Options menus on the method
editor menubar. The debug options are also on the toolbar, which you can show using the
View>>Toolbar menu option. The hierarchy of methods calling other methods is saved in
the method stack and shown on the Stack menu.
You can also check your code using the Method Checker, available under the Tools menu
and described in this chapter.

117

Chapter 4Debugging Methods

Inserting and Editing Methods


You can insert, edit and debug the methods in your library using the Omnis Method Editor.
You can access the method editor in a number of ways, depending on the type of object
youre working on and where you are in Omnis.
To open the method editor for a class

Open your library and view its classes in the Browser

Right-click on the class

Select the Methods option from the context menu

or for window, report, menu, and toolbar classes you can

Open the design screen for the class from the Browser

Right-click on the background of the class design screen

Select the Methods option from the context menu

Code, task, table, and object classes contain methods only, so when you modify these
classes you go straight into the method editor. To add methods to these classes you can
double-click on the class name in the Studio Browser.
The method editor has several different areas, each doing a different job. These are
Menubar and Toolbar
let you add, edit, and execute methods, in addition to debugging the methods in your
application
Variables panes
lets you add variables to the class or method, for example, instance or local variables
Method names and Method definition
lets you add methods to the object, lists existing methods for the object, lets you add
the code for a method, or view the code for an existing method; the method tree list
shows the methods for the class and the individual objects in the class.
You can Right-click on the method tree list to insert a new method (at the end of the
list, or before/after the currently selected method), delete or rename a method, Cut or
Copy a method, or Expand/Collapse the entire method tree.
Command palette
lists all the commands, and the parameters for the current command

118

Debugging Methods
Watch variables pane
lets you monitor variable values while debugging
To insert a method

Right-click on the method list and select Insert New Method, Insert New Method
Before, or Insert New Method After

or

Click on the Modify menu in the method editor toolbar and select Insert New Method

or

Press Ctrl/Cmnd-I while the focus is on the method list

When you have entered the new method name, you can begin to add the code for the
method in the right-hand pane of the method editor.

Line Numbers
You can display a line number for each method line in your code. You can enable line
numbers using the View menu in the Method Editor.

Debugging Methods
You can open most class and field methods and run them from the debugger menu bar or
toolbar. Note that event handling methods will not run from the On command without the
event, but you can try out most types of methods while you are in design mode. You cannot
execute methods that contain instance or task variables at design time since these variables
are only available when the objects are instantiated.
To run or execute a method

Select Debug>>Go from the debugger menu bar

or

Click on the Go button on the debugger toolbar

Execution will begin from the selected line. When you first open the method editor the first
line of the first method is selected. You can halt execution by pressing the stop key
combination Ctrl-Break/Cmnd-period/Ctrl-C. When you break into a method the debugger
completes the current command and halts execution.
The basic debugging operations on the Debug menu are
Go executes from the Go point

119

Chapter 4Debugging Methods


Step executes from the Go point to the next method line, stepping into recipient
methods
Step Over runs from the Go point to the next method line, executing method calls, but
not stepping into them
Trace steps automatically through the method
Set Go Point sets the current method line as the Go point
Go Point Not Set indicates the method with the Go point when one is set
From Line and To Line runs, steps or traces from the current line or to the current line
To Return runs or traces to the return address in the calling method
Read Only Mode prevents editing of methods

The Go Point
A method normally runs from the start, but you can start execution from any method line by
setting it as the Go Point.
To set the Go point

Double-click on the line

or

Select the method line and choose the Debug>>Set Go Point menu option

or

Select the method line and click the Set Go Point button on the toolbar

The debugger highlights this line and puts a yellow arrow in the left margin pointing to the
method line where execution will begin. You can move around the program, changing the
code, without changing the go point, which is independent of the current line. The name of
the method containing the Go point is shown in the Debug menu and choosing this option
from anywhere returns you to the Go point. You can clear the Go point using Stack>>Clear
Method Stack.

Commenting Methods
You can add comments to your code using the ; Comment command. Comments are useful
to document your methods, or temporarily comment out or disable individual lines or
blocks of code. The latter is useful when you are debugging methods.

120

Debugging Methods
To enter a new comment in a method, insert a new line and type ; (semi-colon) while the
focus is in the Command list in the method editor to locate the Comment command. Enter
your comment text in the text box provided.
To comment out existing commands, select the lines of code in the method editor and
press Ctrl/Cmnd-; (semi-colon). To uncomment code, that is, to remove the comment
marks, select the line or lines of code and press Ctrl/Cmnd- (apostrophe). You can also
Right-click on selected lines of code to Comment or Uncomment them.

Execution Errors
When an error occurs in a running method, Omnis takes you into the debugger. The
offending method is displayed with the go point at the method line that encountered the
error, and an error message is shown in the status area. Error messages include the error
number and text, for example E108139: Set main file command with no valid file name.
You can use the various inspection tools to find out why the error occurred, fix it, and
continue.
You can use the Debug>>From Line submenu to run the method from the currently selected
line rather than the go point. The submenu items let you Go, Step, Step Over, or Trace from
the current line instead of from the go point. The To Line submenu lets you Go or Trace
from the go point to the current line, which becomes a one-time breakpoint.

Stepping through a Method


Normally when debugging you will want to step through the code rather than just run it.
This gives much more control over when to start and stop methods and lets you examine
fields, variables, and the method stack at specific points in the program. You use stepping in
conjunction with breakpoints to control the debugging of your code.
To step through a method

Choose Debug>>Step from the debugger menubar, or click on the Step In button

Every time you click on the Step In button, Omnis executes the line at the go point and sets
the go point to the next line. If a command at go point calls another method, the debugger
loads the recipient method on the method stack and sets the go point to the first line in that
method.
The Step In option steps into a recipient method. You can avoid this with Step Over where
the debugger executes the recipient method without stepping into it. This speeds up
debugging if you have a lot of method calls.

121

Chapter 4Debugging Methods

Tracing a Method
As well as stepping through your code, you can record or trace method execution.
To trace a method

Choose Debug>>Trace from the debugger menubar, or click on the Trace button

The debugger steps through your code automatically, including stepping into recipient
methods, and adds each method line and its parameters to a trace log. You open the log
from the Tools menu.
The first column in the trace log shows the name of the currently executing method, and the
class it belongs to. The second column shows the method line and parameters of the
currently executing command. When you double-click on a line in the trace log, the
debugger goes to and highlights that method line.
You can open the trace log from within a method using the Open trace log command. For
example, you can place the Open trace log command in the startup task of your library to
trace method execution immediately after your library opens.
You can specify the maximum number of lines in the log in the Max lines entry field. When
the log contains that many lines, it discards the earliest lines when new ones are added.

Contents of the trace log


The sys(193) function returns the contents of the trace log. It works in both the development
and runtime version of Omnis.

Private Methods
When you step or trace through the methods in your library the debugger will normally
enter each method that is called, even if a method is in a private library. However if you set
the library property $nodebug to true, the debugger will not display methods contained in
private libraries. You need to set this property each time you open the library.

122

Inspecting Variable Values

Inspecting Variable Values


You can inspect the value of a variable or field using the variable context menu. This menu
gives you full information about the variable or field and the class it belongs to, if any. You
can display the variable context menu for any variable or field by right-clicking on its name
in a method or the Catalog. Note that you cannot inspect the value of instance or task
variables in design mode since the variables do not exist: in this case, the variables context
menu is grayed out.
To display a variable context menu

Right-click on the variable or field

This menu contains the variable name, value, parent group and data type, and a series of
debugging options you can apply to the variable. If you click on a variable name in the
variable pane of the method editor, the context menu has the Insert New and Delete
Variable options as well. The other options at the bottom of the context menu are discussed
under Breakpoints. The first option Variable opens the Variable Value window, except that
for Item References with a value, it opens the Notation Inspector.
This window shows the variable name and type at the bottom and displays the value, which
you can edit. Omnis updates the value in the window whenever you bring the window
containing the method to the top, but you cannot observe the value change dynamically
through this window.
On the Variable Value windows View menu
Redraw Values redraws the variable on any window
Single Window Mode shows subsequent variable values in the same window
You can show and edit a list variable in a value window in just the same way. Note you
cannot edit the binary variable.
The value window for a variable is valid only for as long as the variable is current.

The Values List


In addition to the Value window for an individual variable you can show a Values List for
whole groups of variables such as task variables, class variables, and local variables.
To show the Values List for class variables

Right-click on a class variable name in a method or in the catalog

Select the Class Variables option from the variable context menu

123

Chapter 4Debugging Methods


The Values List for class variables appears with the different variable types on tabbed
panes.
On the View menu for the window
Redraw Value redraws the variable wherever it occurs on a window
Show Full Value opens a scrolling Value window below for the selected variable
The Variable popup menu for a file or schema class lets you modify the class, and for file
classes only the Values List shows the current values for the file class.

Watching Variable Values


You can monitor or watch the value of a variable by making it a watched variable. You can
add task, class, local, instance and parameter variables to the Watch variables pane in the
method editor. When you run the debugger you can see the value of a watched variable
change in the Watch variable pane.
To set a watch variable

Right-click on the variable name and choose Watch Variable

or

In the method editor, drag the variable from the variable pane into the watch pane

The Watch Variable item on the context menu is now checked. You can enlarge the watch
pane by dragging its borders. The watch variable value is only updated when stepping,
unless the method redraws it.
To remove a watch variable

124

Right-click on the variable name and uncheck Watch Variable on the popup menu

Breakpoints

Breakpoints
A breakpoint is a marker on a method line. When the debugger reaches that line, it stops
execution and makes that line the go point. When a breakpoint is encountered and you have
switched to a different application (such as a browser in the case of debugging JavaScript
Client methods) the Omnis entry in the Windows Task bar will flash and you have to click
the button to return to Omnis to continue debugging.
To set a breakpoint

Select the method line

Choose the Breakpoint option from the Breakpoint menu

or

Click on the Breakpoint button

When you set a breakpoint for a line, a red dot appears in the left margin. A one-time
breakpoint is a breakpoint that the debugger removes immediately after you break on it. It is
marked by a blue dot in the margin.
When you close a library, you lose all breakpoints in the methods in that library. You can
use the Breakpoint command in a method to set permanent breakpoints, but you must be
careful using permanent breakpoints since you may forget to remove them and they may be
encountered in your application when it is deployed to end users!
The Breakpoint menu lets you create and clear breakpoints.
Breakpoint (Ctrl/Cmnd-Shift-B)
sets a full breakpoint at the current line
One-time Breakpoint (Ctrl/Cmnd-Shift-O)
sets a one-time breakpoint at the current line
Clear Breakpoints (Ctrl/Cmnd-Shift-C)
clears all the breakpoints
Clear Field Breakpoints (Ctrl/Cmnd-Shift-F)
clears all the field change breakpoints, calculation breakpoints, and min and max
settings (see below)
The rest of the Breakpoint menu is a list of all the current breakpoints. Choosing a
breakpoint from this menu displays the line in the debugger.
You can also set breakpoints and from line to line execution, by right-clicking in the left
margin of the method line or by using the appropriate tools on the toolbar.

125

Chapter 4Debugging Methods

Breaking on Variable Change


In the second half of the variable context menu, there is a group of breakpoint options that
let you set breakpoints based on variable or field values.
The debugger only tests for variable or field breakpoints when methods are running, so a
variable change during an enter data suspension of a method will be immediately reported if
there is a control method and delayed otherwise. If there are several variable breaks at the
same command, the debugger only displays one. Setting a variable value breakpoint slows
down method execution considerably.
The menu option Break on Variable Change tells the debugger to stop the method when
the variable value changes. The debugger puts a check mark against the line. Reselecting
the same line toggles the break off. The status line displays the text Break on variable
change (field) when the break occurs.
The One-Time Breakpoint option puts a single-stop variable change breakpoint on the
line.

Breaking on Calculation
You can also create a variable value breakpoint with a calculation. For example, to stop a
method when a local variable lvLines becomes equal to the number of lines in list cvList,
the calculation is entered as
lvLines = lst(cvList,cvList.$linecount)

The menu option Break On Calculation sets the breakpoint, and the following line Set
Calculation prompts for the calculation. The debugger treats the calculation value as a
boolean value where zero corresponds to No and anything else corresponds to Yes.
Execution breaks when the calculation evaluates to Yes, but with a qualification: the break
happens only when the calculation changes from No to Yes. This means that if the
calculation is always Yes, the break never happens; it also means that the break happens
only when the change is from No to Yes, not every time the calculation evaluates to Yes.
For example, the calculation break
(lvNumber<10) | (lvNumber>20)

ensures that local variable lvNumber stays within the range 10-20.
Each variable or field can have one calculation breakpoint. There is no requirement that the
calculation refers to the variable.
The Store Min And Max option adds the minimum and maximum variable values to the
end of the menu as execution proceeds, along with the item Clear Min and Max that lets
you turn off the feature. If you choose either menu item, Omnis writes a line to the trace log.
Turning on Store Min And Max slows down the debugger a good deal.

126

The Method Stack

The Method Stack


A stack is a list of things that you can access in a last-in, first-out manner. When you call a
method, Omnis pushes the current method onto the method stack of executing methods. The
debugger adds each new method to the Stack menu in the method editor. The top-most
menu item is the latest method, the one below it called it, and so on. When a method
returns, Omnis removes the top item, also known as popping the stack, and goes to the
calling method. You can examine any method on the stack by selecting it. You can also
move up and down the stack with the Stack menu items Move Up Stack and Move Down
Stack.
If you select a method in a different class while holding down the Shift key, the debugger
opens a new method design window.
When you stop in a method with a breakpoint, an error, a step, or an explicit stop, Omnis
sets the go point to the next method line and saves the stack. It marks the commands in the
methods on the stack that will execute when you return to that method with a gray arrow in
the left margin pointing to the method line where execution will resume.
A method can appear more than once in the method stack with a completely different set of
local variables.
Debug>>To Return runs or traces the method from the go point or current line until it
returns control to the method that called it. If the only method on the stack is the current
method, this option is grayed out.
There are times when you may want to throw away the current stack and start over. For
example, if you follow a problem to its conclusion and everything freezes up, you can
restart by clearing the stack. You do this with Stack>>Clear Method Stack, which also
grays out the To Return item and removes the Go point.

Method stack list


The sys(192) function returns a list representing the current method call stack, with a line
for each line in the debugger stack menu. The first line in the list corresponds to the call to
sys(192), and subsequent lines correspond to how the method running the previous line was
called.

127

Chapter 4Debugging Methods


The list has 6 columns:
Column

Description

classitem

Item reference to the class containing the method.

object

The name of the object containing the method in the


class; empty if it is a class method.

method

The name of the method.

line

The line number in the method, of the method line


resulting in the method on the previous line running.

linetext

The text for the method line.

params

The parameters passed to the method. This is a two


column list, with the column name and value (the value
displayed as a tooltip for the parameter).

The sys(192) functions works in both the development and runtime version of Omnis.

Debugger Options
The debugger Options menu appears with the other debugger menus.
Debug Next Event
stops at the first line of a method executed for an enter-data event with a control
method (a field method, a window control method or a timer method). Note this option
is not saved with other debugger options and defaults to off whenever Omnis is started
Trace All Methods
sets trace mode permanently on.
Open Trace Log
opens the trace log window or brings it to the top
Disable Debugger at Errors
stops Omnis from breaking into the debugger on program errors; this is what the end
user of your application would see
Disable Debugger Method Commands
deactivates any debugger commands in the methods
Save Debugger Options saves all the debugger options, and Revert To Saved Options
reverts back to the last saved set of debugger options

128

Debugger Commands

Debugger Commands
You can control the debugger using the commands in the Debugger... group. See the Omnis
Help for a complete description of the following commands. Note that none of the
Debugger commands will work in client executed methods in the JavaScript Client,
however, while developing your app, you can use the Send to trace log command in a client
method to write a line to the JavaScript console.
Breakpoint breaks the program when Omnis executes it. If you specify a message, it appears
on the status line when the break happens. Trace on switches trace mode on, optionally
clearing the trace log, and Trace off switches trace mode off.
Send to trace log adds a new line to the trace log containing the specified text. The text can
contain variable names enclosed in square brackets. You can then use the log as a notepad
for your comments, variable or field values, and bookmarks in the code. If you enable the
Diagnostic message option in the Send to trace log command Omnis will send the message
to the trace log substituting any variable values where appropriate. To enable diagnostic
messages in the trace log, you must right-click on the trace log and select the Log
Diagnostic Messages option.
You can double-click on lines in the trace log to open the method editor at the appropriate
point in the method.
The Variable menu command applies a variable context menu option to a list of variables.
The list has the same format as Define list, and for fields can include file names and so on.
This command has several options.
Set break on field change
sets a field change breakpoint for each field in the list
Clear break on field change
clears any field change breakpoints for each field in the list or all breakpoints if you
dont specify a field list
Set break on calculation
sets a calculated breakpoint for each field in the list; set the calculation for each field
with Set break calculation
Clear break on calculation
clears any calculated breakpoints for each field in the list or all calculated breakpoints
if you dont specify a list
Store min and max
stores minimum and maximum values for each field in the list
Do not store min and max
clears store min and max mode for each field on the list or all modes set if you dont
specify a list
129

Chapter 4Debugging Methods


Add to watch variables list
adds each specified field to the watch variables pane
Remove from watch variables list
removes each specified variable from the watch variables pane or all variables if you
dont specify a list. Variables with breakpoints or with store min and max mode set
always appear on the watch variables list
Send value to trace log adds a line to the trace log for each field on the list; if you dont
specify a list, adds a line for all fields
Send minimum to trace log adds a line to the trace log with the minimum for each field
on the list for which the debugger is storing minimums; if you dont specify a list, adds
a line for all such fields
Send maximum to trace log adds a line to the trace log with the maximum for each field
on the list for which the debugger is storing maximums; if you dont specify a list, it
adds a line for all such fields
Send all to trace log adds a value line to the trace log for each field on the list; also
adds minimum and maximum lines to the trace log for each field on the list for which
Store min and max is set; with no list, adds a line for all appropriate fields
Open value window opens a value window for each field on the list; with no list, opens
a window for all fields with whatever limit the operating system puts on the number of
window instances
Open values list opens a values list containing the value for each field on the list; with
no list, opens a values list for all fields, subject to the operating system limit on the
number of window instances. There is one values list for each file class so if more than
one field name from a particular file class appears in the list, Omnis displays only one
values list for that file class
Set break calculation sets up the calculation for the field breakpoint

Checking Methods
You can check the methods in your library using the method checker. The method checker
is available under the Tools menu on the main Omnis menu bar. It checks your code for
syntax errors, unused variables, methods without code, and so on. It provides various levels
of checking and reports errors in individual classes or all classes in the current library. It is
particularly useful for checking libraries converted from an earlier version of Omnis.
Note that the method checker does not correct the code in your libraries automatically, it
simply reports any errors and potential problems in your code.
When you open the method checker it loads all libraries that are currently open.
Alternatively you can open a particular library from within the method checker.
130

Checking Methods
To check the methods in your library

Select the Tools>>Add-ons>>Method Checker menu item from the main Omnis menu
bar
If you need to load a library, click on the Open Library button on the method checker
menu bar
Double-click on the library you want to check
Shift-click or Ctrl/Cmnd-click to select the classes you want to check, or click on the
Select all classes button to select them all

The following checking levels are available


Error conditions
this level of checking finds problems that can cause runtime errors or undesired
behavior; you must fix these errors
Include Level 1 warnings
finds problems that you should investigate because they might result in subtle bugs and
strange behavior; you ought to fix these problems
Include Level 2 warnings
finds problems that you should be aware of, including empty methods and/or inefficient
code, potential compatibility problems, and platform-dependent code
The different levels of checking are inclusive, that is, if you select Level 2 Warnings (the
default) this includes Level 1 and the Errors categories.

Select a checking level, and click on the Check button

The method checker works through the classes you selected displaying their statistics in the
Method Checker Error Log. You can cancel checking at any time by pressing CtrlBreak/Cmnd-period/Ctrl-C.
When checking is complete, you can sort the log by clicking on one of the headers in the
list. You can print the log or save it to a text file.
You can show a summary of the errors for each class by clicking on the Show Summary
button.

Interpreting Errors and Warnings


The following sections detail the different levels of errors and the possible action you
should take.

Fatal Errors
These are the type of errors that you must fix.
131

Chapter 4Debugging Methods


Encountered a construct End without a construct Begin
An ending construct was found without a matching beginning:
End if, End switch, End while, End for, Until, End reversible block
Method contains a construct Begin without a construct End
A beginning construct was encountered without the proper ending:
If, Switch, While, For, Repeat, Begin reversible block
Construct End does not match construct Begin
An ending construct was encountered that did not match the beginning construct, e.g. Begin
reversible block followed by an End if.
Encountered a construct element in an invalid context
One of the following was found outside of a proper construct: Else, Case, Default
Encountered a command in an invalid context
One of the following commands was found outside of a proper construct: Break to end of
switch outside of a Switch construct, or Break to end of loop or Jump to start of loop
outside of a For, While, or Repeat loop.
Incomplete command
A command with no parameters set, for example, Set reference with no reference, Set
current list with no list name, Call method with no method name.
Invalid field reference
An invalid reference to a field or variable (i.e. #???) was encountered: usually a reference to
a field or variable that has been deleted.
Invalid method reference
Encountered a command containing a reference to a non-existent method, an unnamed
method, or a method in a library that is not currently open. For example, Call method with
name of non-existent method, Enable menu line with reference to non-existent menu or
menu line.
Missing extended command or function
A missing extended command or function was encountered, either not loaded or installed:
these show in your code beginning with the letter X.
Bad library name
The library name contains one or more periods.

Level 1 warnings
These are the type of problems that you ought to fix.
Class variable with the same name as a library variable
Could cause precedence problems at the class level.
Optimize method command not in first line of method
The Optimize method command should be the first line of a method.
132

Checking Methods
Code in an unnamed method
Named method with no code
Check to see if this code/method is required.
Debugging code?
You should remove all breakpoints before deploying your application. One of the following
was encountered: Breakpoint, Trace on/off, Field menu command, Set break calculation,
Send to trace log.
Debugging message?
Either OK message or Sound bell was encountered: remove messages inserted for
debugging purposes.
Obsolete command
You should not use obsolete commands: remove them from your code. For example you can
replace Call method with Do method or Do code method.
Command removed by converter
In converted libraries certain commands are commented out: you should use another
command or use the equivalent notation.

Level 2 warnings
These are the type of problems that you should investigate that might require fixing.
Unused variable
Variable defined but unused, or referenced and not defined.
Unfriendly code: Code which could affect other libraries if running in a multi-library
environment
For example, Clear method stack, Quit all methods, Close all windows, Remove all menus.
Unfriendly code: Code which would cause the current library to be closed
The following commands will close the current library if the Do not close other libraries
is not set: Open library, Create library, Prompt for library.
Class name specified in an internal method call
Inefficient code.
Code that modifies a library or class
One of the Classes... group of commands, such as New class, Rename class, Delete class.
Platform-dependent code
Functions which return different values depending on which platform they are executed,
including sys(6), sys(10) to sys(22), sys(103) to sys(114).
Comment containing a question mark
Usually indicates code that needs to be tested, completed, or fixed.
Reference to hash variable
Avoid using hash variables: replace with variable of appropriate scope.
133

Chapter 4Debugging Methods

Method Performance
Omnis Studio allows you to collect data about the performance of method execution in your
application.

Collecting Performance Data


The Omnis root preference $collectperformancedata enables method performance data
collection. Its property is a kCPD... constant specifying whether or not and how Omnis will
collect data about method execution performance. The data collected is stored with each
method in its class, and can be accessed using the notation. Data is not collected for remote
form client methods. The kCPD... constants are:
kCPDnone
Omnis does not collect method execution performance data
kCPDallMethods
Omnis collects method execution performance data for all methods
kCPDmarkedClasses
Omnis collects method execution performance data for methods in classes where the
class property $collectperformancedata is kTrue; see below
Classes that can contain methods also have a new property called $collectperformancedata.
This property is applied only when $root.$prefs.$collectperformancedata has the value
kCPDmarkedClasses. If true, method execution performance data is collected for all
methods in the class.
Assuming $root.$prefs.$collectperformancedata allows, the collected data is stored with
each method in the class, with the following properties for each method:
$callcount
The total number of calls to the method. You can only assign zero to $callcount, in
which case Omnis also sets $totalexecutiontime, $minexecutiontime and
$maxexecutiontime to zero
$minexecutiontime
The execution time in milliseconds of the shortest call to the method
$maxexecutiontime
The execution time in milliseconds of the longest call to the method
$totalexecutiontime
The total execution time in milliseconds of all calls to the method
$minexecutiontime, $maxexecutiontime and $totalexecutiontime are floating point numbers.

134

Sequence Logging
Classes that contain methods, and can therefore collect method performance data, have two
new methods:
$clearperformancedata()
Clears the performance data for all methods in the class
$makeperformancedatalist()
Returns a list containing the performance data collected for all methods in the class
There is a very small overhead when data is collected, while there is no impact on
performance when performance data is not being collected.

Sequence Logging
Sequence logging allows you to record all method execution in the Development version of
Omnis or on the Omnis Server which is used for deploying Omnis web and mobile
applications. If your Omnis Server is running multi-threaded mode, sequence logging can
log method execution on multiple server threads.
Sys(3000) turns on sequence logging, and sys(3001) turns it off. Sequence logging writes
every method command executed to a file in the Omnis directory. The name of the file is
reported by an OK message when logging starts. Logging is thread-safe.
The log file can be up to 2mb in size, and when that limit is reached it discards all but the
most recent 256kb and continues logging. Logged lines can be of any length. The log file
name includes the date. The log file is UTF-8 and has a signature to mark it as such.
Each line in the file is prefixed with "N: " where N identifies the thread. Zero is the main
thread. 1-N are Omnis Server threads.
When logging starts, Omnis writes a message to the log file, to allow the developer to
identify logging being started and stopped.

135

Chapter 5Object Oriented Programming

Chapter 5Object
Oriented Programming
This chapter discusses the object-oriented features used in Omnis Studio, including
inheritance, custom properties and methods, and creating and using object classes and
external objects.

Inheritance
When you create a new class you can derive it from an existing class in your library. The
new class is said to be a subclass of the existing class, which is in turn a superclass of the
new class. You can make a subclass from all types of class except code, schema, file, and
search classes. The general rule is that if you can open or instantiate a class, you can make a
subclass of that type of class. Omnis does not support mixed inheritance, that is, you cannot
make a subclass of one type from another type of class.
When you make a subclass, by default, it inherits all the variables, methods, and properties
of its superclass. Window subclasses inherit all the fields and objects on the window
superclass, and menu and toolbar subclasses inherit all menu lines and tools from their
respective superclass.
Inheritance saves you time and effort when you develop your application, since you can
reuse the objects, variables, and methods from a superclass. When you make a change in a
superclass, all its subclasses inherit the change automatically. From a design point of view,
inheritance forces uniformity in your GUI by imposing common properties, and you get a
common set of methods to standardize the behavior of the objects in your library.

Making a Subclass
You can make subclasses from the following types of class.
Window
inherits variables, methods, and properties from its superclass, as well as all fields on
the window superclass
Menu
inherits variables, methods, and properties from its superclass, as well as the menu lines
in the menu superclass

136

Inheritance
Toolbar
inherits variables, methods, and properties from its superclass, as well as the toolbar
controls in the toolbar superclass
Report
inherits variables, methods, and properties from its superclass: note that a report class
does not inherit the fields, sections, and graphics from its superclass
Task
inherits variables and methods from its superclass, but none of its properties
Table
inherits variables and methods from its superclass, and only some of its properties
Object
inherits variables and methods from its superclass, but none of its properties
To make a subclass

Open your library in the Browser and show its classes

Right-click on a class and choose Make Subclass from its context menu

When you make a subclass Omnis creates a new class derived from the selected class. The
new class inherits all the objects, variables, and methods from its superclass. Omnis
supports up to 10 superclass levels, that is, a single class can inherit objects from up to ten
other superclasses that are directly in line with it in the inheritance tree. If you create further
levels of subclass they do not inherit the objects from the superclasses at the top of the tree.
You can view and edit a subclass, as you would any other class, by double-clicking on it in
the Browser. When you edit the methods for a subclass in the method editor, you will see its
inherited variables and methods shown in a color. When you view the properties of a
subclass its inherited properties are shown in a color in the Property Manager. You can set
the color of inherited objects using the inheritedcolor Omnis preference. Note that all the
Appearance and Action properties for a window are inherited too.
Standard properties for the class, such as the window name and class type, are not inherited,
neither are the grid properties. The properties to do with the general appearance of the
window, such as title and hasmenus, are inherited and shown in a color, which defaults to
bright blue. You cannot change inherited properties unless you overload them: their values
are grayed out in the Property Manager. If you change the properties of the superclass, the
changes are reflected in the subclass when you next open it in design mode.

137

Chapter 5Object Oriented Programming


There are some general properties of a class that relate to inheritance. These are
superclass

inheritedorder

issupercomponent
componenticon

the name of the superclass for the current class; the


superclass can be in another library, in which case the class
name is prefixed with the library name
for window classes only, determines where the inherited
fields appear in the tabbing order: by default inherited
fields appear before non-inherited fields on your window
if true the class is shown in the Studio Browser as a
superclass
icon for the superclass when it is shown in the Studio
Browser

Making a Subclass Manually


You can set the superclass property for a class manually, to make it a subclass of the
specified class, either using the notation or in the Property Manager.
However when you make a subclass in this way it does not inherit any of the properties of
the superclass. Only objects are inherited from the superclass. You have to open the
Property Manager and inherit the properties manually using a context menu.
To inherit a property manually

View the properties of the subclass in the Property Manager

Right-click on the property and select Inherit Property from its context menu

If the property cannot be inherited the context menu will display Cannot Inherit and will be
grayed out. If the class does not have a superclass the inheritance context menu does not
appear or is grayed out.
To inherit a method manually

Open the method editor for the subclass

Right-click on the method and select Inherit Method from its context menu

When you inherit a method in this way, Omnis will delete the current method.

Overloading Properties, Methods, and Variables


Having created a class from another class using inheritance you can override or overload
any of its inherited properties, methods, and variables in the Property Manager or the
method editor as appropriate. All inherited objects are shown in a color. To overload an
object, you can Right-click on the object and select Overload from the objects context
menu. Note that for windows, menus, and toolbars you cannot overload or delete inherited

138

Inheritance
fields, menu lines, or toolbar controls. If you dont want certain objects to be displayed in a
subclass you can hide them temporarily at runtime using the notation.
To overload a property

View the properties of the subclass in the Property Manager


Right-click on the inherited property and select Overload Property from its context
menu

When you overload a property its inherited value is copied to the class and becomes
editable in the Property Manager. You can overload any number of inherited properties in
the class and enter values that are local to the class.
To reverse overloading, you Right-click on a property and select Inherit Property: the local
value will be overwritten and the value inherited from the superclass will appear in the
Property Manager.
To override a method

View the methods for the subclass in the method editor

Right-click on the inherited method and select Override Method from its context menu

When you override a method it becomes like a non-inherited method in the class, that is,
you can select it and add code to it.
To reverse this process and inherit the method with the same name from the superclass, you
can right-click on the method and select Inherit Method: the code in the non-inherited
method will be deleted and the inherited method will now be in place. Alternatively, if you
override a method and then delete the local one, the inherited method will reappear when
you close and reopen the class.
To override a variable

View the methods for the subclass in the method editor and click on the appropriate tab
in the variable pane to find your variable
Right-click on the inherited variable and select Override Variable from its context
menu

When you override a variable it becomes like a non-inherited variable in the class and is
only visible in that class.
To reverse this process and inherit the variable with the same name from the superclass, you
can Right-click on the variable and select Inherit Variable.

139

Chapter 5Object Oriented Programming

Inheritance Tree
The Inheritance Tree shows the superclass/subclass structure of the classes in your library.
All classes below a particular class in the hierarchy are subclasses of that class. When you
select a class in the Browser and open the Inheritance Tree it opens with that class selected,
showing its superclasses and subclasses above and below it in the tree.
To open the Inheritance Tree for a class

Select the class in the Browser

Right-click on the class and select Inheritance Tree from its context menu

Showing Superclasses in the Studio Browser


You can show any class that supports inheritance in the Studio Browser by setting its
$issupercomponent property to kTrue. You can specify the icon for a superclass by setting
its $componenticon property. If you create a class from a superclass displayed in the Studio
Browser, the new class will be a subclass of the class in the Studio Browser automatically.
To make a subclass from a supercomponent

Select the target library in the Studio Browser

Click Class Wizard option

Click on the Class Type option

Click on the Subclasses option

At this stage, all the supercomponents of that type (i.e. classes that have their
$issupercomponent set to kTrue) should be displayed in the wizard.

Click the supercomponent (superclass) you want to create a subclass of

Enter a name for the subclass and click on the Create button

Such supercomponents will only appear in the Studio Browser if the library containing it is
open, since the class actually remains in your library and is only displayed in the Studio
Browser.
Note that classes that appear in the Studio Browser in this way cannot be made the default
object for that class.

140

Inheritance

Inheritance Notation
You can use the $makesubclass() method to make a subclass from another class. For
example
Do $windows.Window1.$makesubclass(Window2) Returns ItemRef
; creates Window2 which is a subclass of Window1 in the
; current library, ItemRef contains a reference to the new class

You can test if the current class can be subclassed by testing the $makesubclass() method
with the $cando() method, as follows
If $cclass.$makesubclass().$cando()
Do $cclass.$makesubclass(sClass) Returns ItemRef
; creates a subclass of the current class

The $makesubclass() method has a Boolean optional second argument


(bAddLibPrefixForClib, default kFalse), which when kTrue, causes the $superclass
property of the new subclass to include the library prefix for the current library.
You can test if a particular class is a superclass of another class using the
CLASS.$isa(SUPERCLASS) method as follows
Do $windows.window2.$isa($windows.window1) Returns lresult
; returns true if window1 is a superclass of window2

You can change the superclass of a class by reassigning $superclass


Do $cclass.$superclass.$assign(DiffClassName) Returns lresult

You can test if a property can be inherited using


Do $cclass.$PROPERTYNAME.$isinherited.$canassign() Returns lresult

If a property can be inherited, you can overload or inherit the property by assigning
$isinherited. For example, to overload a property
Do $cclass.$PROPERTYNAME.$isinherited.$assign(kFalse) Returns lresult

A superclass can be in a different library to a subclass. If you open an instance of a subclass


when the superclass is not available, perhaps because the library the superclass belongs to is
not open or has been renamed, a kerrSuperclass error is generated.

Libraryname prefix for subclasses


By default, Omnis does not prefix $superclass with the library name (if both classes are in
the same library). You can manually change the $superclass property to include the library
name if you wish.

Calling Properties and methods


When a property or method name is referenced in a subclass, Omnis looks for it first in the
subclass and progressively up the chain of superclasses in the inheritance tree for the current
141

Chapter 5Object Oriented Programming


library. Therefore if you havent overridden the property or method in the subclass, or at
any other level, the property or method at the top of the inheritance tree will be called. For
example, the following command in a subclass
Do $cinst.$MethodName()
; will call $MethodName() in its superclass

However, if you have overridden a property or method in the subclass the method in the
subclass is called. You can still access the inherited property or method using the $inherited
property. For example, assuming $MethodName() has been overridden in the subclass
Do $cinst.$inherited.$MethodName()
; will call the subclass method
Do $windows.MySubWin.$MethodName().$inherited
; will call $MethodName() in the superclass

Referencing Variables
When a variable is referenced in a subclass, Omnis looks for its value first in the subclass
and progressively up the chain of superclasses in the inheritance tree for the current library.
Therefore if you havent overridden the variable in the subclass, or at any other level, the
value at the top of the inheritance tree is used.
However, if you have overridden a variable in the subclass the value in the subclass is used.
You can access the inherited variable using $inherited.VarName, in which case, the value at
the top of the inheritance tree is used.
A superclass cannot use the instance and class variables of its subclasses, although the
subclass can pass them as parameters to superclass methods. References to class and
instance variables defined in a superclass are tokenized by name and the Remove Unused
Variables check does not detect if a variable is used by a subclass. If an inherited variable
does not exist, its name is displayed as $cinst.VarName in design mode and will create a
runtime error.

Inherited Fields and Objects


All inherited window fields on a window subclass are included in the $objs for an instance.
Since some field names may not be unique, when $objs.name is used Omnis looks first in
the class containing the executing method, then in the superclasses and lastly in the
subclasses. The $objs group for report fields, menu lines, and toolbar controls behave in the
same way as window fields.
You should refer to fields at runtime by name, since at runtime Omnis assigns artificial
$idents to inherited fields. The $order property of a field may also change at runtime to
accommodate inherited fields into the tabbing order.

Do inherited Command
You can use the Do inherited command to run an inherited method from a method in a
subclass. For example, if you have overridden an inherited $construct() method, you can use
142

Custom Properties and Methods


the Do inherited command in the $construct() method of the subclass to execute the
$construct() method in its superclass. You could use this command at the end of the
$construct() method in the subclass to, in effect, run the code in the subclass $construct()
and then the code in the superclass $construct() method.

Custom Properties and Methods


You can add methods to the objects in your library and call them what you like; you execute
these methods from within the class or instance using the Do method command.
You can also create your own properties and methods and execute them using the notation,
as you would the standard properties and methods. These are called custom properties and
custom methods, or collectively they are referred to as custom notation. Custom notation
can only be executed at runtime, in an instance of the class, and applies either to the
instance, or an object contained in the instance.
The name of a custom property or method is case-insensitive. It can be any name starting
with the dollar $ sign, except for the set of names in the following table.
$add

$addafter

$addbefore

$appendlist

$assign

$att

$attcount

$attributes

$canassign

$cando

$canomit

$chain

$chaincount

$class

$count

$data

$default

$deletelines

$desc

$findident

$findname

$first

$fullname

$group

$ident

$insertlines

$insertlist

$inst

$isinherited

$last

$lib

$minparms

$makelist

$maxcachedclasses

$maxparms

$method

$name

$next

$prev

$obj

$ref

$remove

$runapplescript

$sendall

$serialize

$sublen

$subtype

$type

$wind
Any class that can be instantiated can contain custom notation, including window, report,
table, and object classes. In practice you can use custom notation to override the behavior of
the standard notation, or to add your own properties and methods to an object.
With the exception of the names in the above table, if the name of a custom property or
method is the same as a standard one, such as $printrecord(), it will override the standard
one.

143

Chapter 5Object Oriented Programming


You create custom properties and methods for an object in the method editor. You enter
custom notation for a field in the Field Methods for the field, and for a class in the Class
Methods for a class.
The code for a custom method must define the method parameters as you would for any
other method, and then return the result of executing the method.
The code for a custom property typically comprises two methods. The first, called
$propertyname returns the value of the property using the Quit method command. The
second called $propertyname.$assign defines a single parameter, which is the new value to
be assigned to the custom property; this method usually returns a Boolean value, which is
true if the property was successfully assigned. Note that $canassign is always true for
custom properties.
An instance of a class contains whatever custom notation you define in the class, together
with the properties and methods for that type of instance. The object group $attributes
contains all the built-in and custom notation for an instance. You can use $first() and
$next() against $attributes, but $add() and $remove() are not available.
You can reference custom notation using the notation NOTATION.$xyz, where NOTATION is
some notation for an instance of a class and $xyz is the name of your custom property or
method. If you specify parameters, such as NOTATION.$xyz(p1,p2,p3), they are passed as
parameters to the custom method, and a value may be returned.
You can use the Do default command within the code for custom notation , to execute the
default behavior for a property or method with the same name as the custom notation. You
can use the Do redirect command to redirect execution from custom notation in one
instance to another instance containing custom notation with the same name.
To create a custom method

Open the Class or Field methods for your class


Right-click on the method names list, and select Insert New Method from the context
menu
Enter a name for your custom method, including a dollar sign at the beginning of its
name
Enter the code for the custom method as you would any other method

Userinfo property
File, window, report, menu, toolbar, schema, and query classes have the $userinfo property
which you can use to store your own value. The Property Manager only allows you to assign
to $userinfo if its current value is empty, null or has character or integer data type. The data
stored in $userinfo can be of any other type but it must be assigned to the class at runtime
using the $assign() method.

144

Custom Properties and Methods

Using Custom Methods


The following example uses a task class containing a custom method called $printprinter().
You can call this method from anywhere inside the task instance using
Do $ctask.$printprinter()

The $printprinter() method sets the print destination and calls another class method
depending on whether the user is accessing SQL or Omnis data; it contains the following
code
; $printprinter() custom method
Begin reversible block
Send to printer
Set report name REPORT1
End reversible block
If iIsSQL
Do method printSQLData
Else
Begin reversible block
Set search name QUERY1
End reversible block
Do method printOmnisData
End If

The next example uses a window that contains a pane field and a toolbar with three buttons.
When the user clicks on a button, the appropriate pane is selected and various other changes
are made. Each button has a $event() method that calls a custom method called $setpage()
contained in the window class. Note that you can send parameters with the custom method
call, as follows
; $event() method for second toolbar button
Do $cwind.$setpage(2)

145

Chapter 5Object Oriented Programming


The $setpage() custom method contains a parameter variable called pPage, and has the
following code
; $setpage() custom method
Switch pPage
Case 1
Do $cwind.$objs.MainPane.$currentpage.$assign(1)
Do $cwind.$title.$assign('Queries')
Case 2
Do $cwind.$objs.MainPane.$currentpage.$assign(2)
Do $cwind.$toolbars.$add('tbModify1')
; installs another toolbar
Do $cwind.$title.$assign('Modifying')
Case 3
Do $cwind.$objs.MainPane.$currentpage.$assign(3)
Do $cwind.$menus.$add('MReports')
; installs a menu in the window menu bar
Do $cwind.$title.$assign('Reports')
Default
Quit method kFalse
End Switch

The final example uses a window containing a subwindow, which in turn contains a tree list.
The subwindow contains a custom method called $buildtree() that builds and expands the
tree list. You can call the $buildtree() method from the parent window and send it
parameters, using the notation
Do $cwind.$objs.SubWin.$buildtree(lv_ClassList)

The $buildtree() method contains a parameter variable called pv_SourceList of List type
that receives the list passed to it, and a reference variable called TreeRef set to the tree list
field, and contains the following code
; $buildtree() custom method
Do TreeRef.$setnodelist(kRelationalList,0,pv_SourceList)
Do TreeRef.$expand()

146

Object Classes

Object Classes
Object classes let you define your own structured data objects containing variables and
methods. You can create an object variable based on an object class which contains all the
variables and custom methods defined in the class. When you reference an object variable
an instance of the object class is created containing its own set of values. You can store an
object variable instance and its values on a server or Omnis database. The structure and data
handling capabilities of the object instance is defined by the types of variables you add to
the object class; similarly, the behavior of an object variable is defined by the methods you
add to the object class.
Object classes have the general properties of a class and no other special properties. They
can contain class and instance variables, and your own custom methods. You can make a
subclass from an object class, which inherits the methods and variables from the superclass.
To create an object class

Open your library in the Browser

Click on New Class and then the Object option

Name the new object class

Double-click on the object class to modify it

Alternatively, you may want to create an object class using one of the wizards. In this case,
you should click on Class Wizard, then Object, and select one of the wizards.
When you modify an object class, Omnis opens the method editor for the class. This lets
you add variables, and your own custom properties and methods to the class.
When you have set up your object class you can create any other type of Omnis variable
based on your object class: an object variable has type Object and its subtype is the name of
your object class. For example, you can create an instance variable of Object type that
contains the class and instance variables defined in the object class. When you reference a
variable based on an object class you create an instance of that object class. You can call
the methods in the object class with the notation ObjVarName.$MethodName(), where
$MethodName() is any custom method you define in the object class.
You can store object variable instances in an Omnis data file, or in a server database that
stores binary values. When you store an instance of an object variable in a database, the
value of all its contained instance variables are also stored. When the data is read back into
memory the instance is rebuilt with the same instance variable values. In this respect you
can store a complete record or row of data in an object variable.
You can store object instances in a list. Each line of the list will have its own instance of the
object class. Object instances stored in a task, instance, local, or parameter variable belong
147

Chapter 5Object Oriented Programming


to the same task as the instance containing that variable. Similarly object instances stored in
a list or row belong to the same task as the instance containing the list or row variable. All
other object instances have global scope and are instantiated by the default task and belong
to the default task.
You cannot make an object instance a private instance. If you delete the object class an
object variable uses, the object instance will be empty.
An object instance stored as a class variable in a task is destroyed as soon as its original task
is destroyed.
To add variables and methods to an object class

Open your object class in design mode


Right-click in the variable pane of the method editor and select the Add New Variable
option from the context menu
Name the variable, give it a type and subtype as appropriate
Right-click in the Method Names pane of the method editor and select the Add New
Method option from the context menu
Name the method, including the dollar prefix

If you right click on an object variable, and use the Variable <name>... entry in the context
menu, the variables list window opens, initially showing instance variable values.

Using Object Classes


This section describes an invoices example and uses an object class and simple invoices
window; it is intended to show what you can do with object classes, not how to implement a
fully functional invoices application. You can create the data structure required for an
invoice by defining the appropriate variables and custom methods in an object class.
The following example uses an object class called o_Invoice, which contains the variables
you might need in an invoice, such as the invoice ID, quantity, value, and a description of
the invoice item. The o_Invoice object class also contains any custom methods you need to
manipulate the invoice data, such as inserting or fetching invoices from your database. The
methods in the object class contain the following code

148

Object Classes
; $SaveInvoice() method contains
; local var lv_InvoiceRow of type Row and
; local var lv_Bin of type Binary and
; parameter var pv_Object of type Field reference
Do lv_InvoiceRow.$definefromtable(t_Invoices)
Calculate lv_bin as pv_Object
Calculate lv_InvoiceRow.InvoiceObject as lv_bin
Do lv_InvoiceRow.$insert() Returns #F
; $SelectInvoice() method contains
; local var lv_Row of type Row
Do lv_Row.$definefromtable(t_Invoices)
Do lv_Row.$select()
Do lv_Row.$fetch() Returns #S1
Quit method lv_Row.InvoiceObject
; $FetchInvoice() method contains
; local var lv_Row of type Row
Do lv_Row.$definefromtable(t_Invoices)
Do lv_Row.$fetch()
Quit method lv_Row.Inv_Object
; $total() method
Quit method iv_QTY * iv_Value

The invoice window can contain any fields or components you want, but would contain
certain fields that reference the instance variables in your object class, and buttons that call
the methods also in your object class.
The invoice window contains no class methods of its own. All its functionality is defined in
the object class. The window contains a single instance variable called iv_Invoice that is
based on the o_Invoice object class.
The instance variable would have the type Object and its subtype is the name of your object
class, o_Invoice in this case. If the object class is contained in another library, the object
class name is prefixed with the library name.
When you open the invoice window an instance of the object class is created and held in
iv_Invoice. Therefore you can access the instance variables and custom methods defined in
the object class via the instance variable in the window; for example, iv_Invoice.iv_QTY
accesses the quantity value, and iv_Invoice.$SaveInvoice() calls the $SaveInvoice()
method. Each field on the invoice window references a variable in the object class; for
example, the dataname of the quantity field is iv_Invoice.iv_QTY, the dataname of the item
or description field is iv_Invoice.iv_Item, and so on.
The buttons on the invoice window can call the methods defined in the object class, as
follows.

149

Chapter 5Object Oriented Programming


; $event() method for the Select button
On evClick
Do iv_Invoice.$SelectInvoice(iv_Invoice.iv_ID) Returns iv_Invoice
Do $cwind.$redraw()
; $event() method for the Fetch button
On evClick
Do iv_Invoice.$FetchInvoice Returns iv_Invoice
Do $cwind.$redraw()
; $event() method for the Save button
On evClick
Do iv_Invoice.$SaveInvoice(iv_Invoice)

When you enter an invoice and click on the Save button, the $SaveInvoice() method in the
object class is called and the current values in iv_Invoice are passed as a parameter. The
$SaveInvoice() method receives the object instance variable in the parameter pv_Object and
executes the following code
Do lv_InvoiceRow.$definefromtable(t_Invoices)
Calculate lv_bin as pv_Object
Calculate lv_InvoiceRow.InvoiceObject as lv_bin
Do lv_InvoiceRow.$insert() Returns #F

The row variable lv_InvoiceRow is defined from the table class t_Invoices which is linked
to the schema class called s_Invoices which contains the single column called
InvoiceObject. The binary variable lv_bin, which contains the values from your object
instance variable, is assigned to the row variable. The standard $insert() method is executed
which inserts the object variable into your database. The advantage of using an object
variable is that all the values for your invoice are stored in one variable and they can be
inserted into a binary column in your database via a single row variable. If you want to store
object variables in an Omnis database you can create a file class that contains a single field,
called InvoiceObject for example, that has Object type, rather than Binary, and use the
appropriate methods to insert into an Omnis data file.

Libraryname prefix for object variables


There is an "Include library prefix" check box on the object class selection dialog. This
allows you to add the library name to the object class name for the variable, but when the
object class is in the same library you dont need to add the libraryname prefix.

150

Object Classes

Dynamic Object Instances


The object class has a $new() method that lets you create an object instance dynamically
and store it in an object variable, for example
Do $clib.$objects.objectclass.$new(parm1,parm2,...)
Returns objectvar

where parameters parm1 and parm2 are the $construct() parameters for the object instance.
When the instance is assigned, any existing instance in the object variable is destroyed. It
would be normal practice to put no class in the variable pane for object variables which are
to be set up dynamically using $new(), but there is no class checking for instance variables
so no error occurs if the class shown in the variable pane is different from the class of the
new instance.
You can do a similar thing with an external function library if it contains instantiable
objects, such as Fileops. For example
Do Fileops.$objects.fileops.$new() Returns objectvar
Do objectvar.$openfile(pFilename)

The following example uses an Object variable ivSessionObj which has no subtype defined
in the method editor. When this code executes ivSessionObj is instantiated based on the
object class SessionObj which was created using the Session Wizard in Omnis. Once the
object instance exists the $logon() method is called.
Do $clib.$objects.SessionObj.$new() Returns ivSessionObj
; runs $construct() in the SessionObj object class
Do ivSessionObj.$logon()
; runs the $logon() method in SessionObj

Self-contained Object Instances


Object classes have the $selfcontained property. If set to kTrue the class definition is stored
in all instances of the object class. An instance of such an object class is disconnected from
its class and instead relies on its own class data for method and instance variable definitions.
When the object instance is stored on disk the class definition is stored with the instance
data and is used to set up a temporary class whenever the instance is read back into
memory. Any changes to the original object class have no effect on existing instances,
whether on disk or in memory.
Once an instance is self-contained it is always self-contained, but you can change its class
definition by assigning to $class, for example
Do file1.objvar1.$class.$assign($clib.$objects.objectclass1)

causes the class definition stored inside objvar1 to be replaced by the current method and
variable definitions for objectclass1. The instance variable values are maintained provided
the new instance variable definitions are compatible with the old ones (Omnis can handle
151

Chapter 5Object Oriented Programming


small changes in the type of variables but wont carry out substantial conversions). Note
that the old instance variables are matched to the new ones by $ident and not by name, so to
avoid problems the new class should be a descendant of the original class with none of the
original variables having been deleted.
Only the main class is stored with the object instance, inheritance is allowed but any
superclasses must exist in open libraries whenever the instance is present in memory.
Assigning to $class does not change the superclass structure of self-contained instances.

Object References
The Object reference data type provides non-persistent objects that you can control using
notation. Non-persistent means that objects used in this way cannot be stored on disk, and
restored for use later.
You can use the Object reference data type with local, instance, class and task variables.
Object references have no subtype. To create a new Object instance, referenced by an
Object reference variable, you use the methods $newref() and $newstatementref(). These
are analogous to the $new() and $newstatement() methods used to create object variables,
and they can be used wherever $new() and $newstatement() can be used. When created, an
object reference will belong to the current task.
Once you have associated an Object instance with an Object reference variable, you can use
it to call methods just like you would with an Object variable.
The instance associated with an object reference variable will only be destroyed in the
following circumstances:
If you use the $deleteref() method to delete the object.
The library is closed.
Until one of these occurs, Object reference variables can be passed as parameters, copied,
stored in a list column, and so on. All copies of the variable address the same single
instance of the object. As soon as the object is deleted, other references to the object
become invalid. Prior to deleting the object, Omnis calls the destructor method.
Note that this approach means that you must delete objects when you have finished with
them, otherwise significant memory and resource leaks can occur.
There is also a method $listrefs() which you can call to list the instances of an object class,
external object, or in fact all instances created in this way. This is useful both for leakchecking, and for clean-up.
You can use $newref() in conjunction with session pools. The only differences are that
$deleteref() returns the object instance to the pool, rather than destroying it, and $listrefs()
does not include objects from a session pool.

152

Object References
There are two further methods that can be used with object reference variables. $copyref()
creates an object instance which is a copy of the instance referenced by the variable, and
$validref() returns a Boolean which is true if and only if the variable references a valid
object instance. Note that if $copyref() takes a copy of a DAM session object, both copies
reference the same DAM session.
The method $objref() can also be used. If there is an object reference associated with the
instance, the method returns the object reference, otherwise returns #NULL, that is, the
object MUST have been created with a $newref().

Constructing new objects


from an object class
Calculate myObjectReference as
$clib.$objects.myObject.$newref(Test)
from an external object
Calculate myObjectReference as
$extobjects.ODBCDAM.$objects.ODBCSESS.$newref()
from a session object
Calculate myObjectReference as
mySessionObjectReference.$newstatementref()
storing the reference in a list column of type Object reference
Do theList.$add($extobjects.ODBCDAM.$objects.ODBCSESS.$newref())

Listing instances created using an Object


reference
instances of an object class
Calculate myList as $clib.$objects.myObject.$listrefs()
instances of an external object
Calculate myList as
$extobjects.ODBCDAM.$objects.ODBCSESS.$listrefs()
all instances
Calculate myList as $listrefs()

153

Chapter 5Object Oriented Programming

Destructing objects
using an object reference variable
Do myObjectReference.$deleteref()
;; Calls the destructor of
the object instance
all instances referenced by a list column of type Object reference
Do myList.$sendall($ref.1.$deleteref())
using the $listrefs() method
Do
$extobjects.ODBCDAM.$objects.ODBCSESS.$listrefs().$sendall($ref.1
.$deleteref())
Do $libs.DAMTEST.$objects.Doracle8.$listrefs().$sendall(
$ref.1.$deleteref())

Testing an object reference for validity


using an object reference variable
If myObjectReference.$validref()
using a list column of type Object reference
If myList.1.myObjRef.$validref()

Copying an object reference


using an object reference variable
Calculate objectReference as myObjectReference.$copyref()
Using a list column
Calculate objectReference as myList.1.myObjRef.$copyref()

External Objects
External objects are a type of external component that contain methods that you can use by
instantiating an object variable based on the external object. External objects can also
contain static functions that you can call without the need to instantiate the object. These
functions are listed in the Catalog under the Functions pane.
Some external objects are supplied with Omnis Studio; these include equivalents to the
FileOps and FontOps externals, a Timer object, as well as the new multi-threaded DAMs.
Writing your own external objects is very similar to writing external components, which is
described in a separate manual available to download from the Omnis website. The FileOps
and FontOps functions are documented in the Omnis Help.
External objects are created and stored in component libraries in a similar manner to
external components, and in future releases are intended to replace external functions and
commands, although to maintain backward compatibility, the old external interface is still
supported at present.
154

External Objects
External object libraries are placed in the XCOMP folder, along with the visual external
components. They must be loaded in the same way as external components using the
External Components option, available in the Browser when your library is selected.

Using External Objects


You can add a new object in the method editor by inserting a variable of type Object and
using the subtype column to select the appropriate external object. You can click on the
subtype droplist and select an external object from the Select Object dialog. This dialog also
appears when you create an object elsewhere in Omnis, such as the file class editor. An icon
in the variable subtype cell shows whether the variable is based on an object class or an
external object.
When an instance of the external object has been constructed, you can inspect its properties
and methods using the Interface manager.
To use the objects methods in your code, you can drag the method you require from the
Interface Manager into the command parameters box.
For some objects it is important to note that for the Interface manager to interrogate an
object it will need to be constructed. For example if the Interface Manager was used on an
Automation object, the Automation server needs to be started.
External objects are contained in the notation group $extobjects, which you can omit from
notation.

External Object Events


External objects do not support events in the GUI sense. They can however define
notification methods which they call when certain events occur.
You can subclass an external object and then override the notification method so your code
is informed of the event. The Timer object supplied in Omnis is an example of this. To
subclass an object, you can either set the superclass property in the Property Manager, or
use the New Subclass Object wizard available in the Browser (using the Class
Wizard>>Object option).

External Object Notation


All the components available to Omnis are listed in the $root.$components group.
Individual components have their own methods, in addition to the $cmd() method which
allows you to send a component specific command to the component or object.
The following examples show some commands that you can send to an ActiveX component
to manage timeouts:
Do $components.ActiveX.$cmd("RequestPendingTimeout",10000)
; Set timeout in milliseconds

155

Chapter 5Object Oriented Programming


Do $components.ActiveX.$cmd("ServerBusyTimeout",10000)
; Set timeout in milliseconds
Do $components.ActiveX.$cmd("ResponseDialog",kFalse)
; Prevent response dialog from appearing
Do $components.ActiveX.$cmd("BusyDialog",kFalse)
; Prevent busy dialog from appearing

Interface Manager
The Interface Manager displays the public methods and properties for objects in Omnis
Studio, that is, any class that can contain methods and can be instantiated, including
window, menu, toolbar, report, task, table, and object classes (not available for code
classes). Furthermore, for window, report, toolbar, and menu classes the Interface Manager
displays the methods for the objects in the class. For each class or object, the Interface
Manager displays all built-in methods, including those available in the instance of the class,
as well as any custom methods you have added to the object.
Private methods, namely methods with a name that does not begin with a dollar sign, are not
included in the Interface Manager since these methods are confined to the class or instance.
For each method in the class or object, the Interface Manager displays the method name, its
parameters, return types, and a description, if any are present.
You can view the Interface Manager for a class via its context menu or the method editor.
To view the Interface Manager

Right-click on the class in the Browser and select Interface Manager from the context
menu

or from the method editor

Open the method editor for the class

Select View>>Interface Manager from the method editor menubar

The Interface Manager contains a list of objects in the class, that is, for windows and reports
a list of window or report fields, for toolbars a list of toolbar controls, and for menus a list
of menu lines. For other types of class or instance that do not contain objects, such as object
classes, the Interface Manager contains the class methods only. You can click on each
object or field in the left-hand list to view its methods. Built-in methods are shown in the
color specified in the $nosetpropertycolor preference. Inherited methods are shown in the
color specified in the $inheritedcolor preference. The properties tab similarly shows the
objects properties.

156

Interface Manager
The Details pane shows the parameters for the currently selected method. It also lets you
add a description for your own custom methods. The status bar shows the return type for
built-in methods, but not for your own methods, since these can return any type.
The View menu on the Interface Manager menubar lets you open the method editor for the
class, in addition to hiding or showing the built-in methods and details pane.

Dragging methods from the Interface Manager


You can drag a method or property from the method list and drop it on to an edit field in the
method editor, or you can use copy and paste to do the same thing. The method name is
prefixed by a variable name, such as var_name.$methodname() if you opened the
Interface Manager by right-clicking on a variable of type Object. Otherwise the method
name is prefixed by a dot, such as .$methodname(), suitable to concatenate onto a
variable name or some notation in the method editor. In all cases the parameters for the
method are copied too, so they can be used as a template for the actual values you pass to
the method.

157

Chapter 6List Programming

Chapter 6List
Programming
Omnis has two structured data types; the list and the row. A list can hold multiple columns
and rows of data each row having the same column structure, while a row is effectively a
single-row list. You can create lists of strings, lists of records, or lists of lists. You can
define a list from individual variables, or base a list on one of the Omnis SQL data classes,
such as a schema, query, or table class. In this case, the list gets its column definitions from
the columns defined in the SQL class. Each list can hold an unlimited number of lines with
up to 32,000 columns, although you should be aware that the limitations on memory may
limit the number of rows in lists with many columns.
Omnis makes use of lists in many different kinds of programming tasks such as generating
reports, handling sets of data from the server, and importing and exporting data. The list is
the single most important data type in Omnis programming. List variables provide the data
(content) and formatting for many of the visual list components available for JavaScript
remote form classes: the different types of list controls are described in the JavaScript
Components chapter in the Creating Web & Mobile Apps manual.
In this chapter, rows are generally treated the same as lists, that is, you can use a row name
in any command that takes a list name as a parameter. In addition, references to SQL lists in
this chapter refer to lists based on either schema, query, or table classes, which are referred
to collectively as SQL classes.

158

Declaring List or Row Variables

Declaring List or Row Variables


You can create various scopes of list and row variables, including task, class, instance, and
local variables. You declare a list or row variable in the variable pane of the method editor.
The following table summarizes the variable types and their visibility.
List or row
type

When created?

Where visible?

When removed?

Task variable

on opening task

within the task and all


its classes and instances
that belong to the task

on closing task

Class
variable

on opening the
library

within the class and all


its instances

on clearing class
variables or closing
library

Instance
variable

on opening
instance

within the instance only

on closing instance

Local
variable

on running
method

within the method only

when method
terminates

Parameter
variable

on calling the
method

within the recipient


method

returning to the calling


method

To declare a list or row variable

Right-click in the variables pane of the method editor

Select Insert New Variable from the context menu

Enter the variable name

Click in the Type box and choose List or Row from the droplist

Lists in the JavaScript Client


Like all variables you use in Remote forms to be displayed in the JavaScript Client, any list
or row variables that you want to use in a remote form should be declared as instance
variables (or local / parameter as appropriate). Lists can be declared as task variables which
are available to all instances in the current remote task instance.

159

Chapter 6List Programming

Defining List or Row Variables


To define a list or row variable you need to specify its columns. You can do this using
Omnis commands or the notation. You can define a list or row variable
from variables
from a schema, query, or table class
If you want to use a list in a window or remote form (or any class that can be opened), you
should define the list in the $construct() method of the class, or call a method from the
$construct() that defines the list. This ensures the list is defined and in memory ready to be
used in the current instance.

Lists from Variables


To define a list from a number of variables you can use the Define list command, or the
$define() method. For example
;
;
;
;

Declare class variable cvList1 of List type


Declare class variable cvCol1 of Short integer type
Declare class variable cvCol2 of Character type
Declare class variable cvCol3 of type Date Time (Short date
1980..2079)
Set current list {cvList1}
Define list {cvCol1,cvCol2,cvCol3}

This method will define the list cvList1 with the columns cvCol1, cvCol2, cvCol3. You can
define a list with up to 255 columns. The data type of each field or variable defined in the
list determines the data type of the corresponding column in the list.

Lists and Rows from SQL Classes


You can define a list based on one of the SQL classes, that is, a schema, query, or table
class, using the Define list from SQL class command or $definefromsqlclass() method. This
binds the list or row variable to the schema or query class and consequently maps the lists
columns to the server table. When you define a list or row variable from a table class, it
must have its $sqlclassname property set to the associated schema or query class. You can
do this either in the Property Manager or using the notation.
Do $clib.$tables.MyTable.$sqlclassname.$assign('MySchema') ;; or
Do $clib.$tables.MyTable.$sqlclassname.$assign('MyQuery')

The following example defines an instance row variable from a schema class called
'MyPictures':
; create iSqlRow of Row type
Do iSqlRow.$definefromsqlclass('MyPictures')

160

Defining List or Row Variables


The full syntax of the $definefromsqlclass() method is as follows:
$definefromsqlclass(class[,row,parameters])

Where class is a schema, query, or table class (name or item reference to it), and the row
and parameters are optional.
The row parameter affects the columns used when the SQL class is a schema or table
referencing a schema. A row with no columns (or the parameter is omitted) means that the
list is defined using all the columns in the schema. Otherwise if the row is specified each
column in the row becomes the name of a column to add to the list definition from the
schema. The parameters can be a list of parameter values that are passed to $construct() of
the table class instance created by the method.
For example:
Do list.$definefromsqlclass('schema',row('c1,'c2'))

would only include columns c1 and c2 in the list definition.


Do list.$definefromsqlclass('schema')

Would include all the columns in schema.


To include all columns and call $construct with parameters:
Do list.$definefromsqlclass('table',row(),1,2,3)

This method passes parameters 1, 2, 3 to $construct and includes all the columns from the
schema.

SQL table instance methods


When you create a list or row variable based on one of the SQL classes a table instance is
created, so the list or row variable contains the standard properties and methods of a table
instance. Specifically, if you create a variable based on a table class it contains any custom
methods you have added to the table class; these can override the standard table instance
methods. The following standard methods are available for lists based on a SQL class.
$select()
issues a select statement to the server
$fetch(n[,append])
empties the list and fetches the next n rows from the server; for row variables, n is set to
one and the fetched row always replaces any existing data; the append switch is for list
variables and defaults to kFalse which means the list is cleared by default, otherwise if
you pass the append switch as kTrue the fetched rows are added to the end of any
existing data in the list variable
$insert()
inserts a row into the server database (row variables only)

161

Chapter 6List Programming


$update(old_row)
updates a row in the server database (row variables only)
$delete()
deletes a row from the server database (row variables only)
$sqlerror()
reports the type, code and text for an error in processing one of the above methods
These methods offer a powerful mechanism for processing or inserting data on your server
via your SQL list or row variable. For example, to fetch 30 rows into your list
; declare cvList1 of list type
Do cvList1.$definefromsqlclass(MySchema)
Do cvList1.$select() Returns myFlag
;; sends a select
If myFlag = 0
;; checks for errors
OK message {SQL error [sys(131)]: [sys(132)]}
End If
Do MyList.$fetch(30) Returns myFlag
;; fetches 30 rows
; to fetch another 10 rows and add them to your list
Do MyList.$fetch(10,kTrue) Returns myFlag

List/Row subtypes
A schema, query, or table class name can be used as the subtype of a list or row variable,
that is, a class, instance, local, task or parameter variable, or a column in a list or row
defined from a SQL class.
Omnis uses the subtype class to define the list or row, or in the case of parameters, to
identify the expected definition of the list or row, although Omnis does not do anything if
the definition does not match.
Schema classes have a property $createinstancewhensubtype that controls whether or not
there is a table instance associated with a List or Row variable with a schema class as its
subtype; you can set this property in the Property Manager when editing the schema class.
The property defaults to kTrue for existing and newly created schema classes. When using
the schema class exclusively with Web Services, it is likely that the table instance will not
be required, and in this case turning off $createinstancewhensubtype will therefore improve
performance.

162

Building List Variables

Building List Variables


You can build lists
from SQL data
from Omnis data

Building a List from SQL Data


The SQL SELECT statement defines a select table, which is a set of rows on the server that
you can read into Omnis in three ways:
Fetch next row
brings a row into CRB fields defined by a file class
$fetch(n[,append]) table instance method
brings n rows into a list defined from a SQL class
Build list from select table
transfers the select table to the current list as one block of data
To transfer rows:
Do
Do
Do
Do

mylist.$definefromsqlclass(SchemaRef,Lname,Town) ;; define list


MyList.$select() Returns myFlag ;; make select table
MyList.$fetch(10) Returns myFlag ;; fetch 10 rows into list or
MyRow.$fetch() Returns myFlag
;; fetch a row into a row var

To transfer the whole select table use the Build list from select table command:
; Declare class variable cvList of type List
Set current list cvList
Define list {fItems,LVAR1,LVAR5}
; defines the list with all fields from fItems, plus LVAR1 & LVAR5
Build list from select table ;; builds list from SQL query

When loading large select tables into the list, you should avoid making the user wait for the
whole set of rows to arrive before refreshing the screen to display the first fifty or so rows.
You can retrieve the rows in batches using the $linemax property which limits the size of
the list, pausing after each batch to redraw the list field.

163

Chapter 6List Programming

Building a List from Omnis Data


You can build a list from Omnis data using the Build list from file command. It puts all the
rows from an Omnis data file into the current list. For example
Set current list LIST2
Define list (fCustomers)
Build list from file

You can also apply a search and sort with this command; see the Omnis Data Files chapter.
For a list defined from file class or other variables you can add values either as variables or
literals using Add line to list. This adds a line to the end of the list, or inserts a line at the
specified line and shifts other lines down.
Add line to list {('Jones','Ipswich',fCountry)}
;; adds at the end
Add line to list {10('Jones','Ipswich',fCountry)} ;; adds at line 10

Viewing the contents of a list variable


You can view the current contents of a list variable by Right-clicking on the variable name
in the Method Editor and selecting the first option in the context menu. You can do this
wherever the variable name appears in Omnis, including the method editor and Catalog.

List and Row functions


Omnis provides functions for converting independent variables into a row, and for
converting a series of row variables into a list.

The list() Function


The list() function accepts a set of row variables as parameters, and creates a list variable
from them. The definition for the first row variable is used to define the list. If subsequent
row variables have different definitions, Omnis will convert the data types to match the first
row.
Calculate myList as list(myRow1, myRow2, myRow3)

The row() Function


The row() function accepts a set of variables as parameters, and creates a row variable from
them. The variable types are used to define the columns of the row.
Calculate myRow as row(myVar1, myVar2, myVar3)

164

Accessing List Columns and Rows

Accessing List Columns and Rows


You can access data in a list by loading an entire row of data, or an individual cell into other
variables. An entire row of information is loaded with the Load from list command. You can
access individual cells using the Load from list command or the lst() function, or by
referencing the List Row and Column as part of a calculation. Dont confuse lst() with the
list() function discussed in the previous section.
The Load from list command takes an optional set of variables to load data into. In the case
of a list defined from a File class or other variables, the load command will automatically
place each columns data into the fields of the same name. To load a list defined from a
SQL class, you include a list of variables as part of the Load from list command.
Load from list
;; loads the row into a file class
Load from list (Var1, Var2) ;; loads the row into specified vars

You can use the lst() function as part of a calculation to extract a particular cell of
information from a list.
Calculate MyVar as lst(MyList, rowNumber, ColumnName)

You can address cells directly by referring to them as ListVarName.ColumnName for the
current row or ListVarName.RowNumber.ColumnName for a specified row. Omnis also
recognizes the syntax ListName(ColumnName,RowNumber). The column name must be
in quotes.
You can use RowVarName.ColumnName or RowVarName.ColumnNumber when you
assign a row variable to a window edit field. Remember that your list and row variables
should be defined in the $construct() of a form or window so they are available to edit fields
and other data bound objects when the form or window opens.
Since ListName.ColumnName and ListName.RowNumber could be ambiguous, Omnis
assumes character values are column names. In the case of the row number being contained
by a character variable, this should be indicated by adding +0.
Calculate MyNum as MyList.Amount ;; the current row
Calculate MyNum as MyList.5.Amount ;; row 5
Calculate MyNum as MyList(Amount,5) ;; Amount column, row 5

The two types of statement above are also used to assign a value to a list element.
Calculate MyList.5.Amount as 100 ;; sets Amount column, row 5 to 100

List Variable Notation


List variables have certain standard properties and methods that provide information about
the list, such as how many rows or columns it has, or the number of the current line. List

165

Chapter 6List Programming


columns, rows, and cells have properties and methods of their own which are listed in the
Omnis Help (press F1 to open the Omnis Help).

List Properties and Methods


All types of list have the following properties. A list created from a SQL class has the
standard properties and methods of a table instance, together with these list properties.
$linecount
returns the number of lines in the list; you can change this property or use Set final line
number to truncate the list
$linemax
holds the maximum number of lines in the list; this is set to 10,000,000 by default but
you can change it to restrict the list size
$line
holds the current line in the list; this changes when the user clicks on a list line, or when
using a method such as $search()
$colcount
returns the number of columns in the list
$isfixed
true if the list has fixed length columns; changing $isfixed clears the data and the class
for the list, but keeps the column definitions (note that a list defined using $define() has
columns of any length). Fixed length columns improve performance in some cases, but
cannot contain all data types
$class
returns the schema, query, or table class for the list, or is empty if it is not based on a
SQL class
$cols
group containing the columns in the list; you can use $add() to add a column, also
$addbefore() and $addafter() to add a column before or after the specified column
(these methods do not work with schema or table based lists)
$smartlist
Set this property to kTrue to make it a "smart list"; setting $smartlist to kTrue creates
and initializes the history list which tracks changes to the list; setting $smartlist to
kFalse discards the history list completely. If you define or redefine a list using any
mechanism, or add columns to a list, its $smartlist property is set to kFalse
automatically. See later in this chapter for more details about smart lists.
For a row variable, $linecount, $linemax and $line are all set to 1 and cannot be changed.

166

List Variable Notation


Lists also have the following methods.
$define()
without parameters this clears the list definition, otherwise $define(var1[, var2, var3]...)
defines a list using variables or file class fields; the variable names (or column names
from a file class) and var/column types are used to the define the list column names and
types; when using a file class you can append /S to the file class name to skip empty
columns
$definefromsqlclass()
$definefromsqlclass(query/schema/table class[,cCol1,cCol2,...][,,cons-params]) defines
a list or row variable from a query, schema or table class and instantiates a table
instance. Passes cons-params to the table $construct() method
$copydefinition()
$copydefinition(list or row variable[,parm1,parm2]...) clears the list and copies the
definition but not the data from another list or row variable; if the list being copied
from is derived from a SQL class, the parameters are passed to $construct() of the table
instance
$clear()
clears the data for the list, but keeps the list definition
$first()
$first(selected only[, backwards]) sets the current row of the list to the first row or first
selected row and returns a reference to that row
$next()
$next(list row or row number[, selected only, backwards]) sets the current row of the
list to the next row or next selected row and returns a reference to that row
$add()
$add(column1 value[, column2 value]...) inserts a row of values at the end of the list
and returns a reference to the new line
$addbefore()
$addbefore(list row or row number,col1 value[, col2 value]...) inserts a row before the
specified row
$addafter()
$addafter(list row or row number,col1 value[, col2 value]...) adds a row after the
specified row (does not work with schema or table based lists)
$remove()
$remove(list row or row number) deletes the specified row
$search()
$search(calculation[,bFromStart=kTrue,bOnlySelected=kFalse,bSelectMatches=kTrue,
bDeselectNonMatches=kTrue]) searches the list; behaves the same as for the Search

167

Chapter 6List Programming


list command; bOnlySelected restricts the search to selected lines. If bFromStart is
kTrue, Omnis searches all of the lines in the list, starting at line 1; otherwise, Omnis
starts the search at line ($line + 1).
$sort()
$sort(first sort variable or calculation, bDescending [, second sort variable or
calculation, bDescending]...) sorts the list; you can specify up to 9 sort fields, including
the sort order flag bDescending. The sort fields or calculations can use $ref.colname or
list_name.colname to refer to a list column. The sort order flag bDescending defaults to
kFalse (that is, the sort is normally ascending). For calculated sorts, the calculation is
evaluated for line 1 of the list to determine the comparison type (Character, Number or
Date).
$removeduplicates()
$removeduplicates(listname.column) removes all list lines with duplicate values in the
column; you must sort the list before using this method
$merge()
$merge(list or row[, by name, only selected]) merges the two lists; note $merge()
cannot use search criteria to merger data
$totc()
$totc(expression[,bSelectedOnly=kFalse]) totals the expression over all of the lines in
the list; if bSelectedOnly is kTrue, only the selected lines are totaled. It is similar to the
totc() function, except it also works when the list does not have proper field columns,
for example when the list is defined using a SQL class. For example:
Do MyList.$definefromsqlclass('MySchema')
;; the schema has 2
numeric cols, col1 and col2
Do MyList.$add(1.1,2.1)
Do MyList.$add(3.1,4.1)
Do MyList.$add(2.2,1.1)
Do MyList.$totc(MyList.col1+MyList.col2) Returns Total
; outputs Total = 13.7 i.e the total of both columns

Properties and Methods of a List Column


The columns of a list are contained in the List.$cols group. The $cols group has the
following methods, that is, the standard group methods, including the $add methods that
allow you to add columns to the list (but not schema or table based lists):
$add
$add({fieldname|cName,type,sub-type[,iMaxlen=10000000]}) adds a column to the list
and returns an item ref to it; either use just a fieldname (to use the definition of a field)
or a name,type and subtype constants (e.g. kCharacter,kSimplechar) and length

168

List Variable Notation


$addafter()
$addafter(rColumn|iColumnNumber,{fieldname|cName[,type,sub-type,iMaxlen]}) adds
a column to the list and returns an item reference to it
$addbefore()
$addbefore(rColumn|iColumnNumber,{fieldname|cName[,type,sub-type,iMaxlen]})
adds a column to the list and returns an item reference to it
$remove()
$remove(rColumn|iColumnNumber) removes the column from the list
A list column has the following properties:
$name
returns the simple name of the column
$dataname
returns the dataname of the list column; empty for a list defined from a SQL class
$coltype
returns the data type of the column; changing this clears the list data
$colsubtype
returns the data subtype of the column; changing this clears the list data
$colsublen
returns the length of character and national columns; changing this clears the list
List columns have the following methods:
$clear()
Clears the data for a list or row, or a column in a list or row; executing List.$clear() for
a smart list sets $smartlist to kFalse, meaning that it is no longer a smart list
$average()
$average([bSelectedLinesOnly=kFalse]) Returns the average of the non-null list
column values
$minimum()
$minimum([bSelectedLinesOnly=kFalse]) Returns the minimum of the non-null list
column values
$maximum()
$maximum([bSelectedLinesOnly=kFalse]) Returns the maximum of the non-null list
column values
$count()
$count([bSelectedLinesOnly=kFalse]) The count of non-null values in the list column

169

Chapter 6List Programming


$removeduplicates()
$removeduplicates(bSortNow,bIgnoreCase) removes rows with duplicate values in the
column
$total()
$total([bSelectedLinesOnly=kFalse]) Returns the total of the non-null list column
values
Note: $average, $maximum, $minimum and $total are not available in client methods. Also
the bSortNow parameter of $removeduplicates is ignored and always treated as kFalse in
client methods.

Properties and Methods of a List Row


A list row has the following properties:
$group
returns the list containing the row
$selected
returns true if the row is selected
A list row has the following methods:
clear()
clears the value of all the columns in the row
$loadcols()
$loadcols(variable1[, variable2]...) loads the column values for the row into the
specified variables
$assigncols()
$assigncols(column1 value[, column2 value]...) replaces the column values for the row
with the specified values
$assignrow()
$assignrow(row, by name) assigns the column values from the specified row into the
list row on a column by column basis

Properties of a List Cell


If a list cell is itself a list or row variable it has all properties of a list or row. List cells have
the following properties.
$group
returns the list row containing the list cell
$ident
returns the column number for the list cell

170

Manipulating Lists
$name
returns the column name for the list cell
$line
returns the row number for the list cell; not necessarily the current line in the list

Manipulating Lists
You can change both the structure and data of a list variable using both commands and
notation.

Dynamic List Redefinition


You can add, insert, remove, or move columns in list or row variables without losing the
contents of the list or row. This functionality applies to all types of list and row variables
including smart lists.
List.$cols.$add(variable name)
adds a column to the right-hand end of the list using the specified variable name and
type as its definition
List.$cols.$add(colname, type, subtype, length)
adds a column to the right-hand end of the list using the specified definition
List.$cols.$remove(column name or number)
removes the specified column and moves any remaining columns to the left
List.$cols.$addbefore(rColumn|iColumnNumber, {fieldname|cName [,type, sub-type,
iMaxlen]})
inserts a column to the left of the specified column using the specified variable name
and type as its definition (unless type, sub-type, iMaxlen are specified), and moves any
columns to the right as necessary
List.$cols.$addafter(rColumn|iColumnNumber, {fieldname|cName [,type, sub-type,
iMaxlen]})
inserts a column to the right of the specified column using the specified variable name
and type as its definition (unless type, sub-type, iMaxlen are specified), and moves any
columns to the right as necessary
List.$cols.column name or number.$ident.$assign(new column number)
moves the column to a new position and moves other columns to the right or left as
appropriate; in this case the $ident of a list column is its column number, therefore
changing the ident moves the column to a different position
When using List.$cols.$add(colname, type, subtype, length) to add a column, the type and
subtype parameters need to be constants under Data Types and Data Subtypes in the
Catalog (press F9). In addition, the subtype and length are not always required, depending

171

Chapter 6List Programming


on the type of the column. The following method defines a list and then adds a further two
columns to the right of the existing columns.
Do mylist.$define(col1,col2)
Do mylist.$cols.$add('MyCol',kCharacter,kSimplechar,35)
Do mylist.$cols.$add('MyPicture',kPicture)

Note you cannot add a column to a list using square bracket notation or using the fld()
function. In addition, you cannot insert, remove, or move columns in a list defined from a
SQL class, since you cannot redefine schema-, query-, or table-based lists. However you
can use List.$cols.$add() to add extra columns to a SQL list.

Clearing List Data


You can use the command Clear list or ListName.$clear() to clear the data from a list. You
can clear individual columns of a list with the ListName.ColumnName.$clear(), and
individual rows with ListName.rowNumber.$clear().

Searching Lists
You can search a list using the $search() method, and a successful search sets the flag. You
can use a search calculation to search a list as follows:
Do MyList.$search(calculation [,bFromStart=kTrue,
bOnlySelected=kFalse, bSelectMatches=kTrue,
bDeselectNonMatches=kTrue])

For example, to search the Country column for USA you can use:
Do MaiList.$search(Country = USA) Returns myFlag

The search calculation can use list_name.colname to refer to a list column. When searching
a list column in a client method in the JavaScript Client you must prefix the column name
with $ref. For example:
Do iList.$search($ref.iCol="ABC")

With bSelectMatches or bDeselectNonMatches the first line number whose selection state is
changed is returned (or 0 if no selection states are changed), otherwise the first line number
which matches the selection is returned (or 0 if no line is found).

Selecting List Lines


When you display the data in a list variable in a list field on a window, by default you can
select a single line only. However, you can allow multiple selected lines by setting the list or
grid fields $multipleselect property. When the user highlights list lines with the mouse, the
$selected property for those lines is set. If the field does not have $multipleselect set, the
current, selected line is the highlighted one; if the $multipleselect property is set, all
highlighted lines are selected, and the current line is the one with the focus.

172

Manipulating Lists
Some of the commands that operate on a list variable use $selected to indicate their result.
For example, Search list (Select matches) will set $selected for each line that matches the
search criteria.
Each list variable has two select states, the saved and current selections. The current
selection is the set of lines currently selected, whereas the saved selection is the previous set
of lines that was selected before the current selection changed.
There are a number of commands that you can use to manipulate selected lines,
save the current selection, and swap between the selected and saved states. These
commands are described in the Omnis Studio Help.

Merging Lists
You can copy lines from one list to another using the Merge list command or the $merge()
method. Merging copies a specified set of lines from one list, and appends them to another .
The following example copies the selected lines from LIST1 to LIST2 by checking each
lines $selected property.
Set current list LIST2
Set search as calculation {#LSEL}
Merge list LIST1 (Use search)

$merge() provides slightly different capabilities in that it can match the destination columns
by column name as well as by column number. Merge list works by column number only.
The syntax is
$merge(listName, byColumnName, selectedOnly)

The above example could be written as:


Do List2.$merge(List1, kFalse, kTrue)

Note that $merge() does not have a search capability.

Sorting Lists
You can specify up to nine levels of sorting using the Sort list command or $sort() method.
To use Sort list you need to set up the sort fields first, and clear any existing sort levels
since these are cumulative. $sort() clears existing sort fields automatically. For example
Set current list {MyList}
Clear sort fields
Set sort field Country
Set sort field Town
Set sort field Name
Sort list
Redraw lists

173

Chapter 6List Programming


The $sort() method takes the sort variables or column names in order, each followed by a
boolean indicating the sort direction; the sort order flag bDescending defaults to kFalse
(that is, the sort is normally ascending).. Using notation, the equivalent of the above
example would be
; Country, Town, Name are columns in MyList
Do MyList.$sort($ref.Country,kFalse, $ref.Town,kFalse,
$ref.Name,kFalse)
Redraw lists

Removing Duplicate Values


List columns have the $removeduplicates() method which removes lines with duplicate
values in the column. You must sort the list on the column before using this method.
Do MaiList.$sort($ref.CustNum,kFalse)
;; sorts list on CustNum
column
Do MaiList.$cols.CustNum.$removeduplicates() return NumRemoved

Smart Lists
You can track changes made to a list by enabling its $smartlist property. A smart list saves
any changes, such as deleting or inserting rows, in a parallel list called the history list. Smart
lists can be filtered, a process which allows data not meeting a particular criteria to be made
invisible to the user while being maintained in the history list.
A smart list variable therefore contains two lists:
the normal list containing the list data, and
the history list containing the change tracking and filtering information
If you store a smart list as a binary object is a SQL database, all the smart list information is
stored automatically.

Smart Lists and the JavaScript Client


The JavaScript Client does not support smart lists in client executed methods, insofar as if
you change the list in some way on the client, it will no longer be a smart list when the
updated data is sent from the client back to the server.

Enabling Smart List Behavior


To enable the smart list capability of any list variable you have to set its $smartlist property
to kTrue.
Do ListName.$smartlist.$assign(kTrue)

174

;; to enable it

Smart Lists
Setting $smartlist to kTrue creates and initializes the history list. If it is already kTrue, then
setting it again has no effect.
Setting $smartlist to kFalse discards the history list completely. The current normal list
remains unchanged, so the current contents of the normal list are preserved, but all history
and filtering information is lost.
If you define or redefine a list using any mechanism, or add columns to a list, its $smartlist
property is set to kFalse automatically.

The History List


The history list has one row for each row in the normal list, together with a row for each
row that has been deleted or filtered. The history list has the columns contained in the
normal list as well as the following additional columns:
$status
contains the row status, which is one of the constants kRowUnchanged, kRowDeleted,
kRowUpdated, or kRowInserted, reflecting what has happened to the row. Only one
status value applies, so a row that has been changed and then deleted will only show
kDeleted. Note that kRowUpdated is true if the row has changed in anyway, even if the
current values do not differ from the original column values.
$rowpresent
true if the row is still present in the normal list, otherwise, the row is treated as if it has
been deleted
$oldcontents
a read only row variable containing the old contents of the row
$currentcontents
a read only row variable containing the current contents of the row
$errorcode
an integer value that lets you store information about the row; the standard table
instance methods use this to store an error code
$errortext
a text string that lets you store information about the row; the standard table instance
methods use this to store an error text string
$nativeerrorcode
native error code generated by last statement command
$nativeerrortext
native error text generated by last statement command

175

Chapter 6List Programming

Properties of the History List


You can access the history list via the $history property, that is, LIST.$history where LIST
is a smart list. $history has the properties:
$linecount
read-only property that returns the number of rows in the history list
$history also supports the standard group methods $first() and $next() as well as
$makelist(), but you cannot change the history list.

Properties of Rows in the History List


LIST.$history.N refers to the Nth row in the history list. You can use this notation to access
the columns using the following properties:
$status
the status of the row: not assignable
$rowpresent
results in the row being removed from, or added to, the normal list: this is assignable,
but there are several circumstances which cause Omnis itself to change $rowpresent
and override your changes (deleting a row, applying or rolling back a filter, etc.)
$rownumber
the row number of the row in the normal list, or zero if $rowpresent is false; not
assignable
$filterlevel
the number of filters applied to the history list, up to 15: not assignable (see filtering
below)
$oldcontents
the old contents of the row in the normal list: not assignable, but the old contents of the
row can be assigned to the normal list
$currentcontents
the current contents of the row in the normal list: not assignable
$errorcode
the error code for the row; assignable and initially zero
$errortext
the error text for the row; assignable and initially empty
$nativeerrorcode
native error code generated by last statement command
$nativeerrortext
native error text generated by last statement command
176

Smart Lists
The above row properties are also properties of the list rows in the normal list, and provide
a means of going directly to the history data for a line. In this case, $rowpresent is always
kTrue, but can be set to kFalse.

Tracking the Changes


Change tracking occurs automatically as soon as you enable the $smartlist property for a
list. From this time, Omnis automatically updates the status of each row in the history list
whenever it inserts, deletes, or makes the first update to the row. Note that change tracking
only remembers a single change since the history list was created. Hence:
Updating a row of status kRowUnchanged changes it to kRowUpdated; updating a row
with any other status leaves the status unchanged
Inserting a row always sets the status to kRowInserted and makes the row present in the
normal list
Deleting a row always sets the status to kRowdeleted and makes the row not present in
the normal list; the row is still present in the history list (and can be made present in the
normal list) until a $savelistdeletes operation is performed

Change Tracking Methods


The history list has several standard methods that let you undo or accept changes to the list
data. After using any of these methods, the list is still a smart list.
You can use the following methods for accepting changes:
$savelistdeletes()
removes rows with status kRowDeleted from the history list, and also from the normal
list if $rowpresent is kTrue
$savelistinserts()
changes the status of all rows with kRowInserted to kRowUnchanged, and sets the old
contents of those rows to the current contents. It does not change $rowpresent
$savelistupdates()
changes the status of all rows with kRowUpdated to kRowUnchanged and, for all rows,
sets the old contents to the current contents; this does not change $rowpresent
$savelistwork()
quick and easy way to execute $savelistdeletes(), $savelistinserts() and
$savelistupdates()

177

Chapter 6List Programming


And these are for undoing changes made to the list data:
$revertlistdeletes()
changes the status of all kRowDeleted rows to kRowUnchanged or kRowUpdated
(depending on whether the contents have been changed); for these rows $rowpresent is
set to true
$revertlistinserts()
removes any inserted rows from both the normal list and the history list
$revertlistupdates()
changes the status of all kRowUpdated rows to kRowUnchanged and, for all rows, the
current contents are set to the old contents; this does not change $rowpresent
$revertlistwork()
quick way to execute $revertlistdeletes(), $revertlistinserts() and $revertlistupdates()
The history list also has a default method that lets you set the row present property based on
the value of the status.
$includelines(status)
includes rows of a given status, represented by the sum of the status values of the rows
to be included. Thus 0 means no rows, kRowUnchanged + kRowDeleted means
unchanged and deleted rows, and kRowAll means all rows, irrespective of status. This
is a one-off action and does not, for example, mean that rows deleted later will remain
flagged as present

Filtering
Filtering works only for smart lists. You apply a filter by using the $filter() method, for
example
Do ListName.$filter(COL1 = 10) Returns Count

$filter() takes one argument, which is a search calculation similar to one used for $search().
It returns the number of rows rejected from the list by the filter.
Filtering uses the row present indicator of the history list to filter out rows. In other words,
after applying a filter, Omnis has updated $rowpresent to kTrue for each row matching the
search criterion and kFalse for the others. Filtering applies only to the rows in the normal
list, that is, rows where $rowpresent is kTrue, with the result that repeated filtering can be
used to further restrict the lines in the list.

Filter Level
Each history row contains a filter level, initially zero. When you apply the first filter, Omnis
sets the filter level of all rows excluded by the filter to one; that is, for each row in the
normal list, for which $rowpresent becomes kFalse, $filterlevel becomes one. Similarly for
the nth filter applied, Omnis sets $filterlevel for the newly excluded rows to n. You can
apply up to 15 filter levels.
178

Smart Lists
Whenever a row is made present, for whatever reason, the filter level is set back to zero,
and whenever the row is made not present, for any reason other than applying a filter, the
filter level is also set back to zero.

Undoing a Filter
You can restore filtered rows to the normal list using the $unfilter() method, for example:
Do ListName.$unfilter() Returns Count

When called with no parameters, $unfilter() removes the latest filter applied. Otherwise,
$unfilter removes filters back to the level indicated by the parameter. Thus $unfilter(0)
removes all filters, $unfilter(1) removes all but the first, and so on.

Reapplying a Filter
You can reapply all the filters which have already been applied, in the same order, to all
lines present in the normal list using the $refilter() method. For example
Do ListName.$refilter() Returns Count

The Filters Group


A list has a read-only group called $filters which lets you navigate through a list of the
filters that have been applied. For example
ListName.$filters.N

identifies the Nth filter currently applied to the list, that is, the filter which filtered out rows
at filter level N. Each member of the $filters group has a single property,
$searchcalculation, which is the text for the search calculation passed to $filter() when
applying the filter.

Sorting smart lists


When a smart list is sorted, Omnis sorts the second list. This list does not contain selection
states, these are only stored in the first list, therefore using $selected when sorting a smart
list is not supported.

Committing Changes to the Server


The current state of the normal list can be committed to the corresponding server table,
assuming the list was defined from a SQL class, using the following smart list methods
$doinserts(), $dodeletes(), $doupdates()
inserts, deletes, or updates any rows in the list with the row status kRowInserted,
kRowDeleted, or kRowUpdated, respectively
$dowork()
executes the above methods one after the other, in the order delete, update, insert

179

Chapter 6List Programming

List Commands and Smart Lists


Any command or notation which defines a list sets $smartlist to false, so that any history
information is lost. You can use the following list commands and notation with smart lists
but with particular effects.
Search list and equivalent notation selects only lines in the normal list.
Sort list and equivalent notation, includes all rows, even those with $rowpresent set to
false, so that if those lines become present in the normal list they will be included in the
correct position.
When using Merge list or equivalent notation, if the source list is a smart list only its
normal list is merged, not the history information. If the destination list is a smart list
the merged lines are treated as insertions and have the status kRowInserted.
When using Set final line number, if lines are added they are treated as insertions and
have the status kRowInserted, and if lines are removed they are treated as deletions and
are kRowDeleted.
Using a Build list... command gives all lines the status kRowInserted. This performance
overhead can be avoided by not setting $smartlist until after the list is built.

180

Smart Lists

Chapter 7SQL
Programming
The SQL Browser lets you connect to your server database quickly and easily, and the SQL
Form wizards let you build the interface to your server database. However you may want to
modify the SQL forms created automatically or create forms from scratch to enhance your
web and mobile apps. To do this, you use the SQL methods.
This chapter covers features of SQL programming that are common to all supported
databases. The current version of Omnis Studio supports the following server databases:
Oracle 7, 8, 9i, 10g & 11g
Sybase Adaptive Server Enterprise 12 and Sybase SQL Anywhere 9-11
DB2 Universal Server 7 9.x
PostgreSQL 8.x
MySQL 4.1 5.x
all ODBC- and JDBC-compliant databases, such as MS SQL Server 200x & MS
Access 2000
plus you can access an Omnis database (data file) using Omnis SQL
For information about features that are particular to individual supported databases, see the
Server-Specific Programming chapter.

Note to existing Omnis users


The Data Access Modules (DAMs) previously referred to as non-visual or V3 DAMs
are now known as Object DAMs. Where reference is made to a DAM it is assumed to be
the new Object DAM type unless stated otherwise. By default, the Omnis Session Manager
now displays only those session templates that use the new Object DAMs. If you want to
use older style (V2) DAMs, you can enable them from the SQL Browser: Options tab.

181

Chapter 7SQL Programming

Overview
The Object DAMs (Data Access Modules) provide an object-oriented mechanism for
establishing connections to a variety of SQL databases and enable you to perform multithreaded database access as part of an Omnis Server in a web application. The DAM
interface uses objects to represent a database session and session statements. These objects
provide properties and methods that let you invoke the required database functionality.
Using the object-oriented approach, an application creates object variables of a particular
DAM class that are instantiated when the object is created by the component. This is known
as a session object and represents a session of one of the supported DAM types. There is a
group of common operations that apply to all session objects and a set of database specific
operations based on the type of session object. For example, if an application requires an
ODBC session, it uses an ODBCSESS session object. The session object controls the
connection environment used to pass commands to the database server. The application
creates a statement object in order to issue SQL. A statement object can be used for all
types of statements, e.g., SQL, PL/SQL, cursors and remote procedures. There can be
multiple statement objects which share a common context provided by a single session
object.
In the Omnis Server multi-threaded environment there will be multiple clients each
accessing session objects on the same server. Although it is possible to allow each client to
use its own object this may use large amounts of system resource. Therefore, additional
functionality is provided to create and maintain session object pools where each is of the
same type. An application can allocate session objects from this pool. Each object in the
pool is connected with the same attributes when the pool is created. This has an advantage
in performance when a client requests an object since the connection is immediately
available.

Setting up a Database Connection


To connect to one of the supported databases, you may need to install the appropriate
clientware on each machine that will be connecting to your server. The DAM uses this
clientware to connect to the remote server.
We recommend which third party clientware you can use for each of the supported
platforms and DAM connections. This information is available on the Omnis web site:
www.omnis.net/dams. For each database type, a recommended driver name and version is
provided. This is the driver which we have tested and certified against and which we
recommend you to use.
For most platform/database combinations however, there will be other drivers which work
comparably. In the event of technical support issues, it is the drivers listed on our web site
which we ask faults be verified against.

182

Connecting to your Database

INI files under Mac OS X


Certain object DAMs available for Mac OS X, namely; DAMODBC, DAMSYBSE and
DAMORA8 make use of .ini files in order to set system environment variables to be
required by their associated client libraries. These files are named after the DAMs to which
they apply and reside inside the Omnis package; in the Contents:MacOs:xcomp:ini
folder.
If running Omnis from the command line (i.e. using the open omnis.app command),
you can set environment variables from the context of the terminal window before starting
Omnis- hence negating the need for these files. If used however, their values will override
any existing values.

Connecting to your Database


Aside from hostname, username and password information, the session templates in the
SQL Browser contain all the necessary information required to connect to your server
database automatically. However, to connect to your database programmatically you need to
create a session object and log the session object onto the database.
The session object is the primary object that controls the session environment from which
statement objects are created. This includes the connection, the transaction mode and any
common statement properties such as the size of large object data chunks. The instance of
an object is created either explicitly via the $new() external object method, or where it is
first used. This initializes the object with default property values. When the object goes out
of scope or is closed explicitly, depending on the session state, any statements are closed
and the connection is logged off.

183

Chapter 7SQL Programming

Creating a Session Object


Create a variable of data type Object in the Variable Pane of the method editor and set the
subtype to the session type required for the database connection.
Connection

Session Type

Oracle

ORACLE8SESS

Sybase

SYBASESESS

DB2

DB2SESS

PostgreSQL

PGSQLSESS

MySQL

MYSQLSESS

ODBC

ODBCSESS

JDBC

JDBCSESS

Omnis SQL

OMSQLSESS

Note that most of these will only appear in the list of available session types if the relevant
client software has been installed on your computer. DAM objects that fail to load due to
missing or incompatible client software will leave an entry in the Trace Log when Omnis is
started.
Any type of variable may be used to create a session object. However, a task variable is
particularly suitable since it enables a variety of objects within your library to easily access
the database session.
See the section on External Objects in the Object Oriented Programming chapter for further
information about creating object variables.

Logging a Session Object On and Off


The $logon() method is used to log on to the host server using a valid username and
password. This establishes a connection that this session can then use to send commands to
the server.
You can log on to a database using a method call of the form:
Do SessObj.$logon(pHostName,pUserName,pPassword,pSessionName)
Returns #F

The parameters pHostName, pUserName, pPassword contain information required to


connect to the host database. The values of these parameters vary according to the session
object and database. If the pUserName and pPassword parameters are left empty, and
depending on the session object type, the user may be prompted by the database client to
enter the information. See the chapter on Server-Specific Programming for more
information.

184

Interacting with your Server


The optional parameter pSessionName is used to name the new session object and results in
the session appearing under the SQL Browser tab and in the notational group; $sessions.
If the $logon() method is successful, it returns a value of kTrue, a connection to the
database is created and the $state property is set to kSessionLoggedOn. The read-only
properties $hostname, $username and $password of the session object are set to the values
that were supplied.
For example, to log on to a session named MySession to a SQL Server data source named
MyDb using an object variable SessObj
Do SessObj.$logon('MyDb','','','MySession') Returns #F

There is no limit to the number of session objects that you can create, except the limits
imposed by memory resources and server restrictions.
You need to log your session off from the server when you have finished with it using the
$logoff() method.
The connection is dropped and the session $state property is set to kSessionLoggedOff.
Depending on the session state, statements are cleared, cursors used by statements are
closed and pending results are cleared. This call will fail if the session is not currently
logged on. If it fails for any other reason, the connection may be in an undefined state and
the current object should be destroyed. If there was an active transaction on this session, the
behavior of the DBMS will determine if that transaction is committed or rolled back. The
$hostname, $username and $password properties are cleared.

Interacting with your Server


Once a user is logged into a server, they can make use of all the tables and views to which
they have been granted access.
In order to send SQL commands to the server a statement object must first be created.

Creating a Statement Object


A new statement object is created using the $newstatement() method. In order to return a
new statement object in variable StatementObj with name MySql use
Do SessObj.$newstatement(MySql) Returns StatementObj

The statement object can then be used to send commands and process results.
The variable StatementObj is defined as an object variable with no subtype. Again any type
of variable may be used but a task variable is convenient to enable a variety of objects
within your library to easily access the statement and its results.

185

Chapter 7SQL Programming


If successful a statement object is returned otherwise this call has no effect possibly due to
insufficient resources. The new object has a $statementname property value of MySql and
defaults for all other properties.
If the parameter to $newstatement() is omitted, each statement name is automatically
generated. These names are of the form statement_1, statement_2, etc.

Mapping the Data


Before a client application can get any data from a server, it must set up a corresponding
place in Omnis to hold the data. This involves mapping the structure of the data, including
column names and data types. Typically, you do this using Omnis schema classes. You can
define a schema to include all columns of the server table or view, or any subset of the
columns. In addition you can create query classes that use columns from one or more
schema classes.
You can use schema and query classes to define list and row variables to handle your server
data. Information on creating schema, query, and table classes will be found earlier in this
manual, as will details on using list and row variables.

Sending SQL to the Server


To send SQL to the server, you can either write your own methods, or use the table instance
methods that generate SQL automatically and handle both single row and bulk SQL
transactions. SQL statements must first be prepared and then executed. If the statement
returns results these may then be fetched.

Preparing a SQL Statement


When a SQL statement is prepared, it is sent to the server for verification and if valid is
ready to be executed. A single line SQL statement may be prepared using the $prepare()
method. Omnis sends to the server whatever you pass as a parameter to the method. It can
be standard SQL or any other command statement the server can understand. For example
Do StatementObj.$prepare('SELECT * FROM authors ORDER BY
au_lname,au_fname') Returns #F

A value of kTrue is returned if the statement was successfully prepared, kFalse otherwise
indicating that an error occurred. See the section on Error Handling for more information.
Once a statement has been successfully prepared, the value of the $state property is set to
kStatementStatePrepared.

186

Interacting with your Server


A SQL statement may also be built up using a number of lines of method code as follows:
Begin statement
Sta: SELECT * FROM titles
If iPrice>0
Sta: WHERE price>=[iPrice]
End if
Sta: ORDER BY title
End statement
Do StatementObj.$prepare() Returns #F

The Begin statement and End statement block contains the SQL statement each line of
which is contained in an Sta: command. Other method commands such as If, End if etc. may
be included inside the block in order to build up the SQL statement using logic.
Note that in this case a $prepare() method with no parameters is used to prepare the
statement block.
When an Omnis web server is operating in a multi-threaded mode, the $prepare() method
uses the statement buffer of the current method stack.
Once a SQL statement has been prepared it is possible to obtain the contents of the
statement as a text string using the $sqltext property, for example
OK message The current SQL is {[StatementObj.$sqltext]}

The Get statement command returns a copy of the statement buffer created by the Begin
statement, End statement and Sta: commands. Get statement also replaces the bind variable
place-holders in the copy of the statement it returns, with the normal Omnis syntax for bind
variables ("@[...]").

Executing a SQL Statement


After a SQL statement has been prepared, using the $prepare() method, it can be executed.
This is done using the $execute() method. For example
Do StatementObj.$execute() Returns #F

A value of kTrue is returned if the statement was successfully executed, kFalse otherwise
indicating that an error occurred. If the statement $state property is kStatementStateClear
prior to the execution of this method it will fail. Once a statement has been successfully
executed, the value of the $state property is set to kStatementStateExecuted.
If the SQL statement generates results (e.g. a SELECT command), the $resultspending
property of the statement is set to kTrue. These results may be retrieved using the $fetch()
method.
Once a statement has been executed it may be re-executed as many times as is required
using the $execute() method. There is no need to prepare it again unless a different SQL
command is required. Re-executing a statement that has $resultspending set to kTrue will
clear the results set however.
187

Chapter 7SQL Programming


Alternatively, you can prepare and execute a SQL statement with a single command using
the $execdirect() method. For example
Do StatementObj.$execdirect('SELECT * FROM authors ORDER BY
au_lname,au_fname') Returns #F

This method effectively performs a $prepare() followed by a $execute() method and if


successful returns a value of kTrue. Once a statement has been successfully executed, the
value of the $state property is set to kStatementStateExecDirect. It is not possible to reexecute a statement using $execute that has previously been executed using $execdirect().

Fetching Results
When a SQL statement is executed that returns results (e.g. a SELECT statement), these can
be retrieved using the $fetch() method in the form
Do StatementObj.$fetch(pTableRef,pRowCount,pAppend) Returns
lFetchStatus

The results are placed in pTableRef, which may be a list or row variable. The pTableRef
parameter may be omitted only if a previous $fetch() defined the row or list to use for
returning data.
The pRowCount is a positive integer used to specify the number of results rows to return. It
can also be set to kFetchAll to signal that all remaining rows in the result set should be
returned. When pTableRef is a list, the number of rows returned is pRowCount or less. If
pTableRef is a row variable, $fetch() always returns 1 row. If pRowCount is greater than the
number of rows in the current result set, only the available rows are returned. If there are no
more rows left in the current set, kFetchFinished is returned, otherwise kFetchOK is
returned. If the pAppend parameter has a value of kTrue, the rows returned are appended to
the list, or if kFalse, replace the previous contents of the list.
If the row or list is undefined, its column definition is created based upon the names of the
columns in the result set and the results are retrieved. This can be forced by defining the
variable as empty prior to fetching any rows. For example
Do iResultsList.$define()
Do StatementObj.$fetch(iResultsList,9999) Returns lFetchStatus

If the variable was previously defined and the definition of the list or row columns do not
match the data returned, any valid conversions are performed. If there are no more results
pending, the $resultspending property of the statement is set to kFalse. An attempt to fetch
when $resultspending is kFalse will result in a return status of kFetchError.
To limit the number of rows returned to a list use set the value of pRowCount to a value
that will not make the list too big. For example
Do StatementObj.$fetch(iResultsList,100,kTrue) Returns lFetchStatus

The number of rows to be returned is in this case up to 100. If there were more than 100
rows in the results set, the extra rows will remain waiting to be fetched. The pAppend
188

Interacting with your Server


parameter is set to kTrue indicating that the results rows are to be added to the end of the
list, preserving existing rows.
You can use the $linemax list property to limit the size of the list regardless of the number
of rows in the results set. For example to limit the size of a list to 50 rows
Calculate iResultsList.$linemax as 50
Do StatementObj.$fetch(iResultsList,9999) Returns lFetchStatus

Any results generated by a statement will be available until either they have all been fetched
or another query is executed using the same statement object, in which case the previous
results set is destroyed.

Fetching Directly in to Omnis Variables


To return a row of data without using a list or row variable, the $fetchinto() method can be
used in the form
Do StatementObj.$fetchinto(vVar1, vVar2, vVarN) Returns
lFetchStatus

$fetchinto() returns a row of data directly into the parameters supplied. A variable number
of parameters can be supplied corresponding to each column in the result set .

Fetching in to an External File


The $fetchtofile() method lets you fetch a results set to an external file. It is the object DAM
equivalent of the old-style command Retrieve rows to file, allowing one or more rows from
a result set to be written directly into an external text file (export file).
$fetchtofile() implicitly opens and closes the export file, so also encompasses the old-style
commands: Set client import file name, Open client import file, Close client import file and
Delete client import file.
As with the $fetch() and $fetchinto() methods, a result set must exist before you call
$fetchtofile(). The syntax used for $fetchtofile() is:
Do StatementObj.$fetchtofile(cFilename [,iRowCount=1]
[,bAppend=kTrue] [,bColumnNames=kTrue]
[,iEncoding=kUniTypeUTF8/kUniTypeLatin1])
returns Long integer

cFilename is the full path of the export file, formatted as required by the curremt operating
system. The filename will usually be given the extension .txt
iRowCount is an optional parameter which specifies the number of rows to write to the
export file. If iRowCount is less than the number of rows in the result set, $fetchtofile () can
be executed again in which case the result set will be fetched from the last unread row. To
retrieve all rows in the result set to the file, specify kFetchAll. If omitted, a single row is
written.
bAppend is an optional parameter which specifies whether the existing file contents should
be appended to or over-written. The default is to append the data (kTrue).
189

Chapter 7SQL Programming


bColumnNames is an optional parameter which specifies that the first row of the file
should contain the column names of the result set. This has no effect when bAppend is set to
kTrue. The default behavior will automatically write column names to a file which is empty
or being overwritten.
iEncoding is an optional parameter which specifies the type of encoding to be used.
iEncoding should be one of the Unicode type constants and defaults to kUniTypeUTF8. The
corresponding Unicode byte order marker (BOM) is written to the beginning of the file
when the file is empty or when bAppend is set to kFalse.
$fetchtofile() automatically creates the export file if it does not exist or otherwise opens the
file prior to writing the pending result rows into it. The file is closed immediately on writing
the last row.
$fetchtofile() will return kFetchOk or kFetchFinished if the requested rows are successfully
written to the export file, otherwise kFetchError is returned with the resulting error message
being written to statement.$errorcode and statement.$errortext.
Two additional statement properties have been added which work in conjunction with the
$fetchtofile() method. These are $columndelimiter and $rowdelimiter which are used to
specify the characters that delimit columns and rows. It may be necessary to change these
properties to match the format expected by an external application. $columndelimiter and
$rowdelimiter accept multiple characters if required (15 characters maximum). The default
value for $columndelimiter is kTab (chr(9)), and $rowdelimiter is kCr (chr(13)).

Batch Fetching
Where the DBMS is capable, it is possible to reduce network traffic when fetching multiple
rows of data from the database by fetching several rows simultaneously (as a single batch),
thus reducing the number of fetches required to return the entire result set.
There are three statement properties to manage batch fetching; $batchsize,
$effectivebatchsize and $maxbuffersize.
By default $batchsize is set to 1, but this can be set to any long integer value. $batchsize
should be set before the SQL SELECT statement is prepared. Changing the $batchsize
automatically clears any results which may be pending on the statement object. When
increasing the batch size, it should be noted that the memory resources required to receive
the row set will increase proportionately.
$maxbuffersize can be used to limit the batch size such that for a given column of result
data, the buffer size calculated as columnSize * batchSize will not exceed the imposed
maximum value. If the maximum buffer size would be exceeded, the batch size is revised
downward at prepare time to accommodate the maximum number of result rows per fetch.
The default value of $maxbuffersize is 32KB but will accept any long integer value greater
than 255.

190

Interacting with your Server


The resulting batch size is assigned to the $effectivebatchsize property (which is read-only).
The value assigned to $batchsize is stored so that when the statement object is re-used,
$effectivebatchsize can be calculated again.
It is not possible to return non-scalar data types using batch fetching. Such types include
Oracle CLOBs and BLOBs which are not stored in the database directly but referenced by
pointers (LOB locators). Thus, the raw data for each column value has to be fetched using a
separate network transaction- negating the potential benefit of using batch fetching.
Batch fetching of large binary data is also prohibitively expensive in terms of memory
requirements; only one or two rows could be fetched in most cases.
For similar reasons, batch fetching is also not supported for column data which is
retrievable via chunks (chunking). If the database supports chunking of fetched data, the
session property $lobthreshold should be set high enough to prevent possible chunking of
any of the result columns.
When preparing a select statement which includes one or more non-scalar or chunk-able
columns, $batchsize will be set back to 1 automatically. For example
Do mylist.$define()
Do tStatement.$batchsize.$assign(3000) Returns #F
;; Not
implemented by all servers
Do tStatement.$prepare('select * from mytable') Returns #F
OK message {$batchsize will be limited to
[tStatement.$effectivebatchsize] for this result set}
Do tStatement.$execute() Returns #F
Do tStatement.$fetch(mylist,kFetchAll) Returns lStatus

The following object DAMs currently support batch fetching: DAMODBC, DAMORA8,
DAMSYBSE & DAMDB2. For database servers which do not support batch fetching, the
$batchsize and $maxbuffersize properties are also read-only.

Describing Results
After executing a SQL statement, you can use the $results() method to obtain information
about the columns contained in the current results set.
The only parameter required is a list variable where the information is to be placed. For
example
Do StatementObj.$results(iResultsList) Returns #F

191

Chapter 7SQL Programming


The returned list will be defined with the following columns and will contain one row for
each column of the pending results set.
Col

Name

Meaning

ColumnName

Name of column.

OmnisData typeText

Omnis data type (description)

SQLData type

Equivalent standard SQL data type (CHARACTER,


NUMBER, DATETIME, ...)

Length

Column width (for character columns)

Scale

Number of decimal places (for numeric cols), empty for


floating numbers

Null

Nulls allowed (kTrue or kFalse)

Substituting Variables Into SQL Commands


You can substitute variables into the SQL statement using concatenation. You must supply
quoted literals for character columns according to the rules imposed by your SQL server.
For example
Do StatementObj.$prepare(con(SELECT * FROM authors WHERE
state=',iState,' ORDER BY au_lname,au_fname)) Returns #F

Note the use of double-quotes around the statement string, since it is necessary to embed
single quotes around the value for the character column.
If you are using the Sta: command to build up a statement, a variable may be substituted
using square bracket notation. For example,
Begin statement
Sta: SELECT * FROM authors
If iState<>''
Sta: WHERE state='[iState]'
End if
Sta: ORDER BY au_lname,au_fname
End statement
Do StatementObj.$prepare() Returns #F

192

Interacting with your Server


Note that using these types of substitution you can only substitute variables containing data
that can be represented by characters (i.e. character and numeric variables.) For other types
of data including binary, pictures and lists you must use bind variables.

Bind Variables
A bind variable allows an Omnis variable to be passed to a SQL statement. Instead of
expanding the expression, Omnis associates, or binds the memory address of the variable to
a SQL variable. To specify a bind variable you place an @ before the opening square
bracket. Omnis evaluates the expression and passes the value to the server directly rather
than substituting it into the SQL statement as text. You can also use this syntax to bind large
fields such as binary, pictures and lists into a SQL statement. For example
Do StatementObj.$prepare('SELECT * FROM authors WHERE state =
@[iState] ORDER BY au_lname,au_fname') Returns #F
Do StatementObj.$prepare(INSERT INTO authors (au_lname,au_fname)
VALUES (@[iRow.au_lname],@[iRow.au_fname]) Returns #F

Alternatively using the Sta: command:


Begin statement
Sta: SELECT * FROM authors
If iState<>''
Sta: WHERE state=@[iState]
End if
Sta: ORDER BY au_lname,au_fname
End statement
Do StatementObj.$prepare() Returns #F

Note that you do not need to place quotes around a value to be substituted by a bind
variable. You must include quotes when using square bracket notation to substitute
character variables, but you dont need to when using bind variables.
Not all database systems allow bind variables; in these cases Omnis will behave as though
they do, but will instead perform literal expansion as though you had entered square bracket
notation instead of bind variables
Generally, using bind variables results in better performance than using square bracket
notation and is more flexible with respect to data representation. You should use square
bracket notation only when the notation expression evaluates to a part of a SQL statement
other than a value reference- such as an entire WHERE clause, or where you know that
simple value substitution is all you need.
If you are inserting NULL data into the database, you should use bind variables, to ensure
that SQL nulls, rather than empty strings are inserted.
Be careful to ensure when using a variable such as a local or instance variable, that it will
still exist at the time when the SQL is executed using the $execute() method. This is not
193

Chapter 7SQL Programming


usually a problem when the $execute() method follows immediately after the $prepare, but
may be if the $execute() method is located elsewhere (i.e. in another method.) It does not
matter if an instance variable is not in scope in the method where the $execute() is located
so long as the variable has not been destroyed by closing the instance that owns it.
Once a statement containing bind variables has been prepared, it can be repeatedly executed
using the $execute() method. The values of the bound variables may be changed before
each call to $execute(), allowing different data to be passed each time. This can greatly
speed up the process of, say, inserting many rows into a server table within a loop.

Constructing SQL Queries From Row Variables


Several methods are provided that allow you to construct SQL queries based on the
definition of the columns of a row or list variable. These methods return partially complete
SQL text that varies according to the session object in use and always includes all columns
from the row or list variable.

$createnames()
To create a new table on the server, you can use the $createnames() method. $createnames()
returns a text string which is a comma delimited list of column names and data types. Use is
of the form:
Calculate lColList as SessObj.$createnames(pRowRef)

Parameter pRowRef is a row or list variable.


This can be used in a SQL CREATE TABLE statement, for example to create a new
database table called publishers based on the definition of the columns in row variable
iPublishersRow
Do StatementObj.$execdirect(con('CREATE TABLE publishers (',
SessObj.$createnames(iPublishersRow),')')) Returns #F

Note that you need to include the parentheses around the column list because they are not
provided by the method.
Depending on the session object, this will create a SQL command similar to
CREATE TABLE publishers (pub_id varchar(4),pub_name varchar(40),city
varchar(20),state varchar(2),country varchar(30))

$insertnames()
To insert a row into a table, you can use the $insertnames() method. $insertnames() returns
a text string that is a comma delimited list of column names and values to be inserted. Use is
of the form:
Calculate lColList as SessObj.$insertnames(pRowRef)

Parameter pRowRef is a row or list variable. If it is a list variable, the values from the
current line (pRowRef.$line) are used.

194

Interacting with your Server


This can be used in a SQL INSERT statement. For example, to insert a row into the table
publishers containing data from the row variable iPublishersRow:
Do StatementObj.$execdirect(con('INSERT INTO publishers ',
SessObj.$insertnames(iPublishersRow))) Returns #F

Note that the method provides the parentheses around the column and values lists and the
VALUES clause automatically.
This will create a SQL command similar to
INSERT INTO publishers (pub_id,pub_name,city,state,country) VALUES
(@[iPublishersRow.pub_id],@[iPublishersRow.pub_name],@[iPublisher
sRow.city],@[iPublishersRow.state],@[iPublishersRow.country])

$updatenames()
To update a row in a table, you can use the $updatenames() method. $updatenames() returns
a text string that is a comma delimited list of column names and values to be updated. Use is
of the form:
Calculate lColList as SessObj.$updatenames(pRowRef)

Parameter pRowRef is a row or list variable. If it is a list variable, the values from the
current line are used.
This can be used in a SQL UPDATE statement. For example, to update a row in the table
publishers containing data from the row variable iPublishersRow:
Do StatementObj.$execdirect(con('UPDATE publishers ',
SessObj.$updatenames(iPublishersRow),' WHERE pub_id =
@[iPublishersRow.pub_id]')) Returns #F

Note that the method provides the SET clause automatically.


This will create a SQL command similar to
UPDATE publishers SET
pub_id=@[iPublishersRow.pub_id],pub_name=@[iPublishersRow.pub_nam
e],city=@[iPublishersRow.city],state=@[iPublishersRow.state],coun
try=@[iPublishersRow.country] WHERE pub_id =
@[iPublishersRow.pub_id]

$selectnames()
To select all columns in a table, you can use the $selectnames() method. $selectnames()
returns a text string that is a comma delimited list of column names to be selected. Use is of
the form:
Calculate lColList as SessObj.$selectnames(pRowRef,pTableName)

Parameter pRowRef is a row or list variable and pTableName is an optional parameter


(default empty) that will prefix column names with the specified table name.
This can be used in a SQL SELECT statement. For example, to select all columns in the
table publishers using the column definition of the list variable iPublishersList:
195

Chapter 7SQL Programming


Do StatementObj.$execdirect(con('SELECT ',
SessObj.$selectnames(iPublishersList),' FROM publishers ORDER BY
pub_name')) Returns #F

This will create a SQL command similar to


SELECT pub_id,pub_name,city,state,country FROM publishers ORDER BY
pub_name

$wherenames()
To locate a row or rows in a table to be updated or deleted you can use the $wherenames()
method. $wherenames() returns a text string that is a comma delimited list of column names
and values. Use is of the form:
Calculate lColList as
SessObj.$wherenames(pRowRef,pTableName,pComparison,pOperator)

Parameter pRowRef is a row or list variable. If it is a list variable, the values from the
current line are used. The remaining parameters are optional, pTableName will prefix
column names with the specified table name, pComparison (default =) is used to specify
an alternative comparison operator (e.g. >, <, >= etc.), pOperator (default AND) is used
to specify an alternative logical operator (i.e. OR.)
This can be used in a SQL UPDATE or DELETE statement. For example, to delete a row in
the table publishers where the column values exactly match all columns in the row
variable iPublishersRow:
Do StatementObj.$execdirect(con('DELETE FROM publishers ',
SessObj.$wherenames(iPublishersRow))) Returns #F

This will create a SQL command containing a WHERE clause similar to


DELETE FROM publishers WHERE pub_id=@[iPublishersRow.pub_id] AND
pub_name=@[iPublishersRow.pub_name] AND
city=@[iPublishersRow.city] AND state=@[iPublishersRow.state] AND
country=@[iPublishersRow.country]

Table and Column names


Table instances and session variables have a property called $quotedidentifier which
determines whether or not table and column names are contained in quotes. If set to kTrue,
table and column name identifiers returned from the $createnames(), $insertnames(),
$updatenames(), $selectnames() and $wherenames() methods will be quoted thus,
facilitating case-sensitive names and names containing spaces. The new property affects
table instance methods as well as session object methods.

SQL Errors
It is possible for an error to occur when a session or statement method is executed. The
error may originate from the session object or in the database. The session or statement
method will indicate that an error has occurred by returning the value kFalse. The value
196

Interacting with your Server


returned by these methods may be placed into any variable. The following example places
the return value in the Omnis flag variable:
Do StatementObj.$execute() Returns #F

The methods will also return a generic (i.e. database independent) code and message
describing the error in the properties $errorcode and $errortext. For example, in the event of
an error occurring, SessObj.$logon() would return an error code in the property
SessObj.$errorcode and an error message in SessObj.$errortext whilst
StatementObj.$execute() would return an error code in StatementObj.$errorcode and
message in StatementObj.$errortext. You can create a method to display the error code and
message. For example:
OK message SQL Error {Code = [StatementObj.$errorcode], Msg =
[StatementObj.$errortext]}

If smart lists are used, the history list row properties $errorcode and $errortext contain the
value of StatementObj.$errorcode and StatementObj.$errortext for each row updated.
Additionally, you can obtain the native error code and message from the server using the
session and statement properties $nativeerrorcode and $nativeerrortext. Some servers may
return more than one combination of native error code and message for a single error.
Currently only Sybase and Microsoft SQL Server behave in this way. When an error occurs
the $errorcode and $errortext will contain a generic error from the session object and the
$nativeerrorcode and $nativeerrortext will contain the first error reported by the server. If
there are further error messages, $nativeerrorpending (a Boolean property of the statement
object) will be set the kTrue. In order to access the next native error code and message, use
the $nextnativeerror() method that will set the $nativeerrorcode and $nativeerrortext
properties to the next error. You can repeatedly call the $nextnativeerror() method until all
errors have been processed ($nativeerrorpending=kFalse). For example
While StatementObj.$nativeerrorpending
Do StatementObj.$nextnativeerror()
OK message SQL Error {Code = [StatementObj.$nativeerrorcode], Msg
= [StatementObj.$nativeerrortext]}]}
End While

All server errors cause the statement method to return a value of kFalse. If you get an error
from a method it does not prevent execution of further methods. You should always test the
return value after execution of a session or statement method and take an appropriate action.

Data Type Mapping


Omnis converts the data in an Omnis field or variable into the corresponding SQL data type.
Since each DAM maps to a wide variety of data types on servers, each DAM determines the
correct conversion for the current server. See the Server-Specific Programming chapter for
details on how each DAM maps SQL data types to Omnis data types and vice versa.

197

Chapter 7SQL Programming

DAMs support for 64-bit Integers


The Studio 6.0 DAMs perform additional data type mappings between Omnis 64-bit
integers and the corresponding large integer data type on the database server. For most
databases this will be BIGINT. The notable exception is Oracle which uses
NUMBER(19,0) instead.
Note also that BIGINT UNSIGNED columns will be converted to signed 64-bit Integers
when fetched into Omnis. In order to preserve such values, a CAST(column as CHAR)
function can be used to fetch the value into a character field.
Where schemas and lists are defined using Integer 64-bit columns, the session objects
$coltext() and $createnames() methods now return the appropriate SQL data type. Integer
32-bit columns retain their previous behavior.

Clearing Statements and Sessions


It is possible to clear individual statement objects back to their default state using the
$clear() method. For example
Do StatementObj.$clear() Returns #F

When used with a statement, the $clear() method will cancel any pending results or
operations on the statement object and set all properties to their default values (except for
$statementname, $usecursor.) The statement object is placed in the kStatementStateClear
state. If the statement is using a cursor, it will be closed.
When used with a session object the $clear() method will clear all statements controlled by
the session object instance. For example:
Do SessObj.$clear() Returns #F

All of the statement objects are placed in a kStatementStateClear state. Depending on the
session state this will clear all SQL text, close all cursors and destroy pending results of all
statement objects owned by the session.

198

Listing Database Objects

Listing Database Objects


Omnis provides statement methods that enable you to access data dictionary information
about any database to which you can connect using a session object. Using these methods,
you can create database-independent code to list objects contained in your server database,
no matter what its type. These methods work by creating results sets as though you had
queried the information from the database. You then use the $fetch() method to read the
results into Omnis.

Listing Tables and Views


The $tables() method generates a results set containing details of tables available to the
statement object. Use is of the form:
Do StatementObj.$tables(pType,pOwner) Returns #F

The parameter pType is used to indicate what types of object are to be listed and may
contain kStatementServerTable to obtain details of all tables, kStatementServerView to
obtain details of all views, or kStatementServerAll (default) to obtain details of all tables
and all views. The parameter pOwner is used to list only objects belonging to a single
named owner and defaults to all owners. For example to create a list of all available tables
and views for all owners:
Do StatementObj.$tables() Returns #F
Do StatementObj.$fetch(iResultsList,9999) Returns lFetchStatus

To create a list of all available views owned by DBO:


Do StatementObj.$tables(kStatementServerView,'DBO') Returns #F
Do StatementObj.$fetch(iResultsList,9999) Returns lFetchStatus

The results set contains the following columns:


Col

Name

Description

Owner

Name of user that owns the database object

TableOrViewName

Name of table or view

TableType

Object type (kStatementServerTable or


kStatementServerView)

Description

Remarks or description for the object where available

DamInfoRow

A row of database specific information about the table


or view. This may be empty for some session objects

199

Chapter 7SQL Programming

Listing Columns
The $columns() method generates a results set containing details of columns for a specified
table or view.
The only parameter required is the name of the database table or view for which column
details are required. For example to create a list of columns in the authors table:
Do StatementObj.$columns('authors') Returns #F
Do StatementObj.$fetch(iResultsList,9999) Returns lFetchStatus

The results set contains the following columns:


Col

Name

Description

DatabaseOrCatalog

Name of database or catalog that contains the object

Owner

Name of user that owns the database object

ColumnName

Name of column

OmnisData typeText

Omnis data type (description)

OmnisData type

Omnis data type (notational)

OmnisDataSubType

Omnis data subtype (notational)

SQLData type

Equivalent standard SQL data type (CHARACTER,


NUMBER, DATETIME, ...)

Length

Column width (for character columns)

Scale

Number of decimal places (for numeric cols), empty for


floating numbers

10

Null

Nulls allowed (kTrue or kFalse)

11

Index

Index exists for column (kTrue or kFalse)

12

PrimaryKey

Column is the primary key (kTrue or kFalse)

13

Description

Remarks or description for the column where available

14

DamInfoRow

A row of database specific information about the column.


This may be empty for some session objects

Listing Indexes
The $indexes() method generates a results set containing details of index columns for a
specified table. Use is of the form:
Do StatementObj.$indexes(pTableName,pType) Returns #F

The parameter pTableName is the table of which indexes are to be listed. The parameter
pType is used to indicate what types of indexes are to be listed and may contain
kStatementIndexUnique (default) to obtain details of unique indexes,

200

Listing Database Objects


kStatementIndexNonUnique to obtain details of non-unique indexes, or kStatementIndexAll
to obtain details of all indexes. For example, to create a list of all indexes for the table
authors:
Do StatementObj.$indexes('authors',kStatementIndexAll) Returns #F
Do StatementObj.$fetch(iResultsList,9999) Returns lFetchStatus

The results set contains the following columns:


Col

Name

Description

DatabaseOrCatalog

Name of database or catalog that contains the object

Owner

Name of user that owns the database object

ColumnName

Name of column contained in index

IndexName

Name of index

Unique

Unique index (kTrue or kFalse)

ColumnPosition

Position of column (integer) in index (1 for normal index,


1,2,3 for column in compound index)

DamInfoRow

A row of database specific information about the index. This


may be empty for some session objects

Building Schema Classes


Using the $makeschema() session method you can make a schema class automatically that
matches the columns in a database table using a command of the form:
Do SessObj.$makeschema(pSchema,pTableName) Returns #F

The parameter pSchema is a reference to an existing schema class that will be overwritten
with the definition from the server table pTableName.
For example, to create a schema called scAuthors from the server table authors:
Do $schemas.$add('scAuthors') Returns #F
Do SessObj.$makeschema($schemas.scAuthors,'authors') Returns #F

Using the $tables() and $makeschema() methods you can obtain a list of tables on the server
and build a schema class for each server table.

201

Chapter 7SQL Programming

Remote Procedures
Omnis provides methods that enable you to list and execute remote procedures that exist in
the database. Support for these methods varies from one database to another, see the chapter
on Server-Specific Programming for more details.

Listing Remote Procedures


The $rpcprocedures() method generates a results set containing details of remote procedures
available to the statement object. Use is of the form:
Do StatementObj.$rpcprocedures(pOwner) Returns #F

The optional parameter pOwner is used to list only objects belonging to a single named
owner and defaults to all owners. For example to create a list of all available remote
procedures for all owners
Do StatementObj.$rpcprocedures() Returns #F
Do StatementObj.$fetch(iResultsList,9999) Returns lFetchStatus

The results set contains the following columns:


Col

Name

Description

DatabaseOrCatalog

Name of database or catalog that contains the object

Owner

Name of user that owns the database object

ProcedureName

Name of remote procedure

DamInfoRow

A row of database specific information about the remote


procedure. This may be empty for some session objects

Listing Remote Procedure Parameters


The $rpcparameters() method generates a results set containing details of all parameters
required by a particular remote procedure. Use is of the form:
Do StatementObj.$rpcparameters(pProcedureName) Returns #F

The parameter pProcedureName is the name of the remote procedure. This parameter may
take the form Database.Owner.Procedure name depending on whether database and owner
qualifiers are supported. The Database and Owner are optional. The use of the qualifier is as
follows.

202

Remote Procedures
Only Procedure name specified
Owner.Procedure name specified

Database.Owner.Procedure name
specified

Return parameter information for all procedures with


specified Procedure name in all available databases.
Return parameter information for all procedures with
specified Procedure name owned by Owner in all
available databases.
Return parameter information for specified procedure
owned by Owner in Database

For example, to create a list of all parameters for remote procedure byroyalty:
Do StatementObj.$rpcparameters('byroyalty') Returns #F
Do StatementObj.$fetch(iResultsList,9999) Returns lFetchStatus

The results set contains the following columns:


Col

Name

Description

OmnisData type

Omnis data type (notational)

OmnisDataSubType

Omnis data subtype (notational)

Length

Column width (for character columns)

PassType

How the parameter is used. One of the constants


kParameterInput, kParameterOutput,
kParameterInputOutput, or kParameterReturnValue.

C5

Reserved for future use.

C6

Reserved for future use.

DatabaseOrCatalog

Name of database or catalog that contains the object.

Owner

Name of user that owns the database object.

ParameterName

Name of the parameter.

10

OmnisData typeText

Omnis data type (description)

11

SQLData type

Equivalent standard SQL data type (CHARACTER,


NUMBER, DATETIME, ...)

12

Scale

Number of decimal places (for numeric cols), empty for


floating numbers

13

DamInfoRow

A row of database specific information about the


parameter. This may be empty for some session objects

Note that columns 1, 2 and 3 are the closest Omnis type to the server type specified in the
server definition of the procedure parameter.

203

Chapter 7SQL Programming

Calling a Remote Procedure


Before you can call a remote procedure, it must first be registered with Omnis using the
session method $rpcdefine().Use is of the form:
Do SessObj.$rpcdefine(pProcedureName,pList) Returns #F

The parameter pProcedureName is the case-sensitive name of the remote procedure that
must exist on the server. If the procedure has previously been defined, the new definition
replaces the old one. The parameter pList defines the parameters and the return value of the
remote procedure. The list must have the same layout as that returned by
$rpcparameters(pProcedureName), except that only the first 4 columns are required. See the
section on Listing Remote Procedure Parameters ($rpcparameters) for details of the list
layout.
The easiest way to define a procedure is to first call $rpcparameters(), fetch the result set
into a list, and pass the list to $rpcdefine(). For example:
Do
Do
Do
Do

iResultsList.$define()
StatementObj.$rpcparameters('byroyalty') Returns #F
StatementObj.$fetch(iResultsList,9999) Returns lFetchStatus
SessObj.$rpcdefine('byroyalty',iResultsList) Returns #F

Once a remote procedure has been defined, it can be invoked using the statement method
$rpc().Use is of the form:
Do StatementObj.$rpc(pProcedureName,pParam1,pParamN) Returns #F

The call to $rpc() will fail if pProcedureName has not been defined using $rpcdefine() or
does not exist on the server. The session object will invoke the specified remote procedure,
using the procedure definition to determine the parameters it needs. If the optional
parameters pParam1pParamN are included, they are passed to the stored procedure.
If the call is successful, any output parameter values are returned. If the procedure has a
return value specified in its definition, it is written to the statement property
$rpcreturnvalue, if not, $rpcreturnvalue is Null. If the call to the procedure generates a
result set, the statement property $resultspending is set to kTrue and these results may be
retrieved using the $fetch() method. Following successful execution of the remote
procedure, the statement $state property will be set to kStatementStateExecDirect. If the
state prior to this call was not kStatementStateClear, any pending result set or unexecuted
SQL statement is cleared.
For example, to invoke the stored procedure byroyalty passing the variable lPercentage to
the 1st parameter and fetch the results set generated by the stored procedure:
Do StatementObj.$rpc('byroyalty',lPercentage) Returns #F
Do StatementObj.$fetch(iResultsList,9999) Returns lFetchStatus

204

Transactions

Transactions
The $transactionmode session property controls the way that transactions are managed.
Depending on the value of this property the session object may automatically manage
transactions or it may be necessary to manage transaction using explicit method calls or
SQL statements.
Some servers do not provide support for transactions. You can determine whether a
particular server allows transactions using the read-only Boolean session property
$allowstransactions which contains kTrue if the server supports transactions or kFalse
otherwise. Some session objects will contain a value of kUnknown in this property until the
session is logged on. If your server does not allow transactions, the properties and methods
described in the section on Transaction Modes below should not be used.

Transaction Modes
You can set the $transactionmode session property using a command of the form:
Do SessObj.$transactionmode.$assign(kSessionTranManual) Returns #F

The potential values for the transaction mode are


kSessionTranAutomatic
This is the default and specifies that all transaction management be provided
automatically.
kSessionTranManual
Enables the application to manage transactions manually using the session methods
$begin(), $commit() and $rollback().
kSessionTranServer
Transaction management is provided by the DBMS.

Automatic Mode
After a SQL statement has successfully executed, i.e. $execute() or $execdirect() returns
kTrue, the current transaction is automatically committed by the session object. If the
command fails, the transaction is rolled back automatically. A new transaction is started
automatically if required after a successful commit or rollback.
Note that since each individual SQL command is committed immediately that it is executed,
automatic mode does not allow for the creation of transactions that contain a number of
SQL commands to be individually prepared and executed prior to a single commit. If this is
required, you should use Manual or Server mode.

Manual Mode
In kSessionTranManual mode you manage transactions manually using session methods.

205

Chapter 7SQL Programming


$begin()
Where required by the session object, use the $begin()method to start a new transaction, for
example:
Do SessObj.$begin() Returns #F

The $begin() method should only be executed where the DBMS does not implicitly start a
transaction. The read-only session property $autobegintran will contain the value kTrue to
indicate for a particular session object that a transaction is automatically started when a
connection is established to the database or the previous transaction is committed or rolled
back, and in this case the $begin() method should not be used. This method may fail if there
is a current transaction or the server does not support nested transactions.
$commit()
Use the $commit()method to commit the current transaction, for example:
Do SessObj.$commit() Returns #F

The $commit() method will fail if the session $state property is kSessionLoggedOff, if the
transaction mode is not kSessionTranManual or if there is no current transaction. With
certain types of session objects this will commit and clear all statements, close any cursors
used by a statement and clear pending results. This will not destroy the statement objects
used by a session. Depending on the value of the session property $autobegintran, the server
may begin a new transaction automatically.
$rollback()
Use the $rollback()method to roll back the current transaction, for example:
Do SessObj.$rollback() Returns #F

The $rollback() method will fail if the $state property is kSessionLoggedOff, if the
transaction mode is not kSessionTranManual or if there is no current transaction. This
method cancels the current transaction. With certain types of session objects this will
rollback and clear all statements, close any cursors used by a statement and clear pending
results. This will not destroy the statement objects used by a session. Depending on the
value of the session property $autobegintran, the server may begin a new transaction
automatically.
The read-only session properties $commitmode and $rollbackmode describe the effect that
the $commit() and $rollback() methods have on statements and their cursors.

206

Transactions
kSessionCommitDelete
kSessionRollbackDelete

kSessionCommitClose
kSessionRollbackClose

kSessionCommitPreserve
kSessionRollbackPreserve

Prepared statements and cursors on all statement objects are


deleted. Any pending results are lost. The statement object
itself is not deleted but will be set to a kStateClear state. To
re-execute the same statement it must first be re-prepared.
Prepared statements and cursors on all statement objects are
closed. Any pending results are lost. A statement can be reexecuted without first being re-prepared. Any statement
objects that have successfully prepared a statement will be in
the kStatePrepared state.
The state of all statements and cursors remains unchanged.

Note that with some session objects these properties may change once a session is logged
on.

Server Mode
Transaction management is provided by the DBMS. The default behavior is determined by
the database, which may for example automatically commit each SQL statement unless you
override the default.
You may also execute SQL BEGIN, COMMIT and ROLLBACK or other statements
depending on the DBMS SQL dialect, to manage transactions manually.
The read-only session property $autobegintran will contain the value kTrue to indicate for a
particular session object that a transaction is automatically started when a connection is
established to the database, or after a SQL COMMIT or ROLLBACK statement. If
$autobegintran is kFalse, an explicit SQL BEGIN statement is required. SQL based
transaction commands should not be used other than in kSessionTranServer mode.
As a general rule it is recommended that either automatic or manual mode should be used in
preference to server mode.
In kSessionTranManual or kSessionTranServer mode the behavior of the DBMS dictates
whether closing a connection commits the current transaction.
The effect of a commit or rollback on existing statement cursors is dependant on the
behavior of the DBMS. In most cases, a commit or rollback will close all cursors in the
session and clear all results sets. This does not destroy the statement object. It may be
possible to re-execute the statement but generally the statement will need to be prepared
again.
Care should be taken to note the circumstances in which commits occur as this can have a
side effect on the processing of other statement objects associated with the session.

207

Chapter 7SQL Programming

Cursor Results Sets


When a statement is executed that generates results, the results set is preserved until another
SQL command is executed. Cursor results sets enable you to process the results of 2 or
more different SQL SELECT commands in parallel using a number of statement objects
that were created from the same session object using the $newstatement() method.
Note: to use multiple concurrent cursors, the session transaction mode usually needs to be
set to kSessionTranManual.
If the database does not implicitly allow for the concurrent processing of multiple results
sets, you need to set the statement property $usecursor to a value of kTrue for each
statement prior to executing the SELECT. This indicates that a statement should be created
via a server-based cursor. It controls the server specific behavior of the $prepare(),
$execute(), $execdirect() and $fetch() methods. In some circumstances, the client will
automatically generate server-based cursors for SQL SELECT statements and therefore this
property is ignored. If the session object manages cursors and the client does not support the
manual generation of cursors, the session object will explicitly issue the SQL cursor
commands.
Currently, DAMs which support the $usecursor property include the JDBC, ODBC and
Sybase DAMs. The Oracle and OmnisSQL DAMs provide $prepareforupdate() and
$posupdate() methods, whilst DB2 provides its own record locking feature.
If the session object has to explicitly issue SQL cursor commands and a statement is
prepared when $usecursor is kTrue, the following will be prefixed to the statement:
DECLARE <$name> CURSOR FOR <$sqlText>

It is important that $sqltext specifies a SQL SELECT statement. Note that the syntax of the
DECLARE and associated SELECT command may vary slightly if a particular server does
not adhere to the SQL-92 standard.
A subsequent $execute() and $fetch() will issue an
OPEN CURSOR <$name> and FETCH CURSOR <$name>.

Depending on the value of $commitmode and $rollbackmode, any pending results set may
be destroyed when a transaction is committed or rolled back.
To ensure that the results sets are not destroyed by an update command you need to set the
transaction mode to kSessionTranManual and commit updates manually when ready using
the $commit method.

208

Cursor Results Sets


For example, to create a new statement, execute and fetch results from a SELECT command
using a cursor:
Do SessObj.$newstatement() Returns StatementObj
Do StatementObj.$usecursor.$assign(kTrue)
Do StatementObj.$execdirect('SELECT * FROM authors ORDER BY
au_lname,au_fname') Returns #F
Calculate lFetchStatus as StatementObj.$fetch(iResultsList,10)

Non-Unicode Compatibility
The DAMs provided with Studio 5.0 are able to function in Unicode or 8-bit compatibility
mode. This means that after converting your existing libraries for use with Studio 5.0, it
should be possible to continue interacting with non-Unicode databases.
In 8-bit compatibility mode, all DAMs

Return non-Unicode character data types via the $createnames() and $coltext
attributes

Bind outgoing character variables using the databases non-Unicode data types

Convert all data inside outgoing character bind variables to single-byte characters

Define incoming character columns using the databases non-Unicode data types

Convert all data inside incoming character bind variables from bytes into the
Omnis character set

Switching to 8-bit compatibility mode


To switch to 8-bit compatibility mode, there is a session property: $unicode- which should
be set to kFalse from its default value of kTrue. This implementation allows multiple
Unicode and 8-bit session objects to exist side by side if required.

Character Mapping
This section is applicable to session objects operating in 8-bit compatibility mode only.
When reading data from a server database, Omnis expects the character set to be the same
as that used in an Omnis data file. The Omnis character set is based on the MacOS extended
character set, but is standard ASCII up to character code 127. Beyond this value, the data
could be in any number of different formats depending on the client software that was used
to enter the data.
When assigned, the $maptable session property identifies files containing translation tables
for character codes read into and sent out of Omnis. For example, suppose you are working
with a database that stores EBCDIC characters. In order to accommodate this database, you
209

Chapter 7SQL Programming


should create an '.IN' map file that translates EBCDIC characters to ASCII characters when
Omnis in reading server data and a matching '.OUT' file that reverses the process by
converting ASCII to EBCDIC characters when Omnis is sending data to the server.
Under Windows and Linux, Omnis uses the same character set as under MacOS, so in the
general case, mixed platform Omnis applications should have no need for character
mapping. However, if the data in a server table was created by another software package,
running under Windows for example, the characters past ASCII code 127 would appear
incorrect when read using Omnis. In this situation the $maptable property should be used to
map the character set.
There are two kinds of character maps: IN and OUT files. IN files are used to translate
characters coming from a server database into Omnis. OUT files are used to translate
characters that travel from Omnis back to a server database.

The Character Map Editor


The Character map editor is accessed via the Add-On tools menu item and enables you to
create character-mapping files. You can change a given character to another character by
entering a numeric code for a new character. The column for the Server Character for both
.IN and .OUT files may not actually represent what the character is on the server. This
column is only provided as a guide. The Numeric value is the true representation in all
cases.
To change a character, select a line in the list box and change the numeric code in the
Server Code edit box. Once the change has been recorded, press the Update button to
update the character map. You can increase/decrease the value in the Server Code edit box
by pressing the button with the left and right arrows. Pressing the left arrow decreases the
value, pressing the right arrow increases the value.
The File menu lets you create new character map files, save, save as, and so on. The Make
Inverse Map option creates the inverse of the current map, that is, it creates an .IN file if
the current file is an .OUT character map, and vice versa.

Using the Map Files


Establish the character mapping tables by setting the session property $maptable to the path
of the two map files. Both files must have the same name but with the extensions .IN and
.OUT and be located in the same folder. The $maptable property establishes both .IN and
.OUT files at the same time. For example:
Do SessObj.$maptable.$assign('C:\Program Files\Tiger Logic\
Charmaps\pubs') Returns #F

In this example, the two map files are called pubs.in and pubs.out.
The session property $charmap controls the mode of character mapping that is to be applied
to the data. Set the character mapping mode using a command of the form:
Do SessObj.$charmap.$assign(pCharMap) Returns #F

210

Cursor Results Sets


The potential values for the character mapping mode parameter pCharMap are
kSessionCharMapOmnis
Use the internal Omnis character set.
kSessionCharMapNative
This is the default and specifies that the client machine character set is to be used.
kSessionCharMapTable
Use the character mapping table specified in the $maptable property. If the $maptable
property is not set and the application attempts to assign kSessionCharMapTable this
fails.
If you wish to use the character mapping tables defined using the $maptable property, you
must set $charmap to kSessionCharMapTable.

Handling Extended Characters


When operating in non-Unicode mode, the session property $codepage determines how 8bit character codes will be interpreted by the DAM. For example when $codepage is set to
kUniTypeAnsiGreek, fetched ANSI extended character codes are interpreted as letters from
the Greek alphabet. Conversely, Greek characters inserted from Omnis are mapped to
character codes from the Greek code page.
Thus, when operating in non-Unicode mode it is important that the value of $codepage
matches with the character set being used by the remote database.
It should also be noted that when inserting data, any Unicode characters which do not
correspond with characters in the selected code page will not be mapped correctly and such
data is liable to loss or truncation.
Omnis character mapping is applied to fetched character data before conversion from the
selected codepage, whilst inserted character data has Omnis character mapping applied after
conversion to the selected code page.

Interpreting 8-bit Data


This section is applicable to the MySQL, PostgreSQL and Openbase DAMs which interface
with their respective client libraries using the UTF-8 encoding .
When operating in Unicode mode, it is possible to receive mixed 8-bit and Unicode datasince UTF-8 character codes 0x00 to 0x7F are identical to ASCII character codes.
Where this data was created using the non-Unicode version of Omnis however, it is possible
that the data may contain ASCII extended characters. In this case, the Unicode DAM will
encounter decoding errors- mistaking the extended characters as UTF-8 encoded bytes.
This issue was not a concern for the non-Unicode version of Omnis Studio since extended
characters were always read and written as bytes- irrespective of the database encoding.

211

Chapter 7SQL Programming


In order to avoid problems when upgrading to the Unicode version of Omnis Studio, it is
advisable to convert tables containing ASCII extended characters to UTF-8. This process is
simplified where the database character set is already set to UTF-8 (as is often the case with
MySQL). All that is required is to read and update each row in the table and repeat this for
all tables used by the application. In so doing, Omnis will convert the 8-bit data to Unicode
and then write the converted Unicode data back to the database.
In order to facilitate this within the DAM, the session property: $validateutf8 is provided.
When set to kTrue (the default), any fetched character data is validated using the rules for
UTF-8 encoding. Where a given text buffer fails validation, it is assumed to be non-Unicode
data and is interpreted accordingly. When written back to the database, all character data
will be converted to UTF-8. Such updates will result in frequently accessed records having
their contents refreshed automatically.
By setting $validateutf8 to kFalse, validation is skipped and the DAM reverts to the
previous behaviour- in which case extended ASCII characters should be avoided.
Aside from the issue of UTF-8 encoded data, the DAMs provided with Studio 5.0 are able
to retrieve non-Unicode data from non-Unicode database columns in either Unicode or 8-bit
compatibility mode. The DAM knows the text capabilities of each character data type and
assigns encoding values to each result column accordingly.
The difference in behaviour when using 8-bit compatibility is that in compatibility mode, it
is also possible to write data back to non-Unicode columns.
In Unicode mode, the DAM assumes that it will be writing to Unicode compatible data
types and this will cause data insertion/encoding mismatch errors if the clientware tries to
insert into non-Unicode database columns.

Character Mapping in Unicode Mode


Character mapping to and from the Omnis character set is also possible where session
objects are operating in Unicode mode. This was previously removed from the Unicode
DAMs since it provided compatibility between the various 8-bit character sets. Where
Unicode DAMs encounter 8-bit data however, the session $codepage property indicates the
ANSI code page which should be used to interpret the data.
In the general case, you cannot insert non-Unicode data when the DAM is operating in
Unicode mode. To insert such data you should switch to 8-bit compatibility mode ( by
assigning $unicode to kFalse).

Server Specific Programming


Certain DAMs, namely DAMORA8 and DAMODBC also provide session properties which
allow mixing of Unicode and 8-bit data when the DAM is operating in Unicode mode.
The Oracle DAM provides $nationaltonvarchar and $nationaltonclob which allows the
Omnis National character subtype to be used with Unicode data, whilst the Character
subtype is reserved for non-Unicode data.
212

Stripping Spaces
The ODBC DAM provides $nationaltowchar which performs a similar function. These
properties are documented further in the Server Specific Programming chapter.
The onus is upon the developer not to put Unicode characters into Character subtypes when
using these properties, otherwise data insertion/encoding mismatch errors will occur.

Stripping Spaces
The session object can automatically strip trailing spaces from data returned from the
server. This functionality is switched on by setting the statement $sqlstripspaces property to
kTrue. The default value for a statement is taken from the session object $sqlstripspaces and
the default for the session is read from $clib.$prefs.$sqlstripspaces.
Some data sources may strip trailing spaces prior to sending it to the session object in which
case this property has no effect.

Treatment of Date Values


The way the session handles partial, empty and NULL valued date columns can be modified
using two properties; sessionObj.$defaultdate and sessionObj.$emptydateisnull.
The $defaultdate property is used to specify default date parts to be used when parts of the
date are omitted at bind time. Parts of the date (day, month and/or year) are also substituted
where the value being inserted would otherwise constitute an invalid date. This property
provides better support for Omnis custom date types, for example DateTime H:N:S.s
which may have a corresponding server type which includes the date. Bind variable values
override default date values for the constituent date parts which are supplied. The default
value for this property is 1 Jan 2000 00:00:00. It is not possible to assign a #NULL value
to $defaultdate.
$emptydateisnull can be used to set all outgoing bound dates with an empty value to NULL.
This applies to date bind variables used in the WHERE clauses of SELECT, UPDATE and
DELETE statements as well as to the input bind variables of INSERT and UPDATE
statements. To insert (or test for) empty date values, it is necessary to set $emptydateisnull
to kFalse and to assign an empty date to $defaultdate.

213

Chapter 7SQL Programming


The implications of these two properties are summarised below:
To
INSERT a NULL date into a datetime
column or
SELECTWHERE a date value is
NULL
INSERT an <empty> date value into a
datetime column
or
SELECTWHERE a date value is
<empty>
INSERT/test for a date in a datetime
column, substituting a default time,
(empty datetimes are treated as NULL) or
INSERT/test for a Time in a datetime
column, substituting a default date,
(empty datetimes are treated as NULL).
INSERT/test for a Date in a datetime
column, substituting a default time,
(empty datetimes take on $defaultdate) or
INSERT/test for a Time in a datetime
column, substituting a default date,
(empty datetimes take on $defaultdate).

Use value

$defaultdate

$emptydateisnull

#NULL
or
<empty>

Ignored

Ignored

Ignored

kTrue

<empty>

<empty>

kFalse

Datetime
value

Default
datetime

kTrue

Datetime
value

Default
datetime

kFalse

Large Objects
When working with large objects (LOBs) there are some properties that may be used to tune
the system so that data is handled and transferred in an efficient way. Large objects include
large text, list, binary, picture data and instances of object classes.

Blob Size
The session property $blobsize defines the maximum size of a binary data item. The default
value for this property is 10MB, but it may be adjusted to conserve memory. Some session
objects may take this value into account when executing a $createnames() method and
resulting data types may vary according to the value of $blobsize.

Chunking Large Objects


In order to pass large objects to the server they are broken down into chunks. This is due to
potential memory limits that exist with some database vendor client APIs. The session
properties $lobchunksize and $lobthreshold represent respectively the size of a single chunk

214

Session Pools
in bytes and the size of object in bytes at which chunking starts. The default value of both of
these properties is 32KB.
This only applies to Omnis Character, Picture, Binary, List and Object data types that are
greater than 255 bytes.
The value of $lobthreshold may be set to any value between 256 bytes and 2GB. Note that
if not set judiciously, this may cause resource problems due to the amount of memory
required to cache an object.
The value of $lobchunksize may be set to any value between 256 and the $lobthreshold.
Due to limitations in the database vendor client API, certain session objects may impose
their own values for the default and maximum chunk sizes.

Session Pools
Pools of session instances can be created when Omnis starts up and made available to any
methods running within Omnis. They are designed to be used by the multi-threaded server
and allow client methods to quickly obtain SQL sessions without the burden of constructing
their own instances.
There is a notation group $root.$sessionpools that contains the current session pools.
Normally the session pools are created by the startup task and exist until Omnis is shut
down. Pooled sessions do not appear in the SQL Browser.
When a session is required in order to perform a SQL query, it is obtained from the pool
using an object variable and a statement object created in the normal way in order to
execute the query and fetch any results. When the session object variable is destroyed the
session instance is returned to the pool for later reuse.

Creating a Session Pool


Session pools are created using the $makepool() session object method. The syntax of the
method is:
$makepool(name[,count=0,hostname,username,password,initmethod])
; creates a pool of session objects

The call to $makepool() will only be successful if used with an external object that is a
session object or an object class that has a session object as its subtype, that is, the external
server object is its superclass. The $makepool() method returns a reference to the pool if it
is successfully created and the required number of session instances are constructed,
otherwise it returns NULL. Once a session pool has been created there is no need to
maintain it further during the time that the library is open, however it is possible to change
the number of available instances using notation.

215

Chapter 7SQL Programming


Errors encountered when creating session pools are returned via #ERRCODE and
#ERRTEXT.

Using $makepool() with an External Object


Create a session pool using an external object with a method call of the form:
Do $extobjects.DAMobject.$objects.SessObject.$makepool(pPoolName,
pCount,pHostName,pUserName,pPassword) Returns lPoolRef

DAMobject is the name of the external component. You can find out what DAM objects are
available on your workstation by examining the $root.$extobjects branch of the notation
tree using the Notation Inspector. SessObject is the name of the session object. You can find
out what session object is available by expanding the $objects group for a particular DAM
object using the Notation Inspector. The pPoolName parameter is the name of the pool and
must be unique amongst session pools and the pCount parameter is the number of object
instances to be initially contained in the pool. The other parameters are optional and if
specified are passed to the $logon() method for the instance. If they are not specified, the
instance is constructed but not logged on.
For example, to create a session pool called poolone containing 5 sessions all logged on
to SQL Server
Calculate lHostName as 'SqlServer'
Calculate lUserName as ''
Calculate lPassword as ''
Do $extobjects.ODBCDAM.$objects.ODBCSESS.$makepool('poolone',5,
lHostName,lUserName,lPassword) Returns lPoolRef

Using $makepool() with an Object Class


Alternatively $makepool() may be used with an object class with a method call of the form
Do $objects.ObjectClass.$makepool( pName,pCount,pHostname,
pUserName,pPassword) Returns lPoolRef

ObjectClass is the name of an object class that must have a session object as its superclass.
You can achieve this by selecting the object class in the browser and clicking on the
$superclass in the Property Manager, click the arrow and select External Objects and
double-click on the required session object.
For example:
Do $objects.odbcobj.$makepool('pooltwo',10,lHostName,lUserName,
lPassword) Returns lPoolRef

Initializing session objects


The makepool() method has a sixth parameter that allows you to pass the name of an
initialization method to the session object in the form class.method. The initialization
method needs to have a parameter at position 1 of Object Reference type. This method is

216

Session Pools
called for each session added to the pool. The Object Reference Parameter will contain a
reference to the newly created session which can be used to initialize the session object.

Obtaining a Session Instance From a Pool


The $new() method is used to assign a session instance from a pool. For example
Calculate SessObj as $sessionpools.poolone.$new()

If $new() is successful the session instance assigned from the pool belongs to SessObj and
is normally returned to the pool when SessObj is destroyed (for example, if SessObj is a
local variable the session is returned to the pool when the method containing SessObj
terminates). Alternatively the session can be manually returned to the pool by assigning
some other object or zero to SessObj. The $new method returns NULL if all instances
contained in the pool have already been assigned out.
Now you can use the $newstatement() method with the session object to create a statement
to execute SQL in the normal way.

Session Pool Notation


The group $sessionpools supports the usual $findname(), $first(), $next() and $makelist()
notation. The $remove() method is also implemented but not $add() since $makepool() is
used to create a session pool.
A pool has the $name, $poolsize and $inuse properties. The $poolsize property is the
number of instances stored in the pool and $inuse is the number of these which are currently
assigned out. If you increase the value of $poolsize the new session instances are
immediately constructed and if the hostname, username and password parameters were
specified at $makepool, they are also logged on.
You can use poolRef.$poolsize.$assign(poolRef.$poolsize-1) to reduce the pool size, that
is, to destroy a session instance in the pool, providing enough sessions are available to be
destroyed. If not, then the pool size is reduced as and when sessions are returned to the
pool. Note that the $poolsize property reflects the actual number of active sessions and not
necessarily the number of sessions required by the user.
An alternative form of the $new() method is poolone.$new(pWaitSeconds) which is
designed to be used in client methods running on the multi-threaded server. If there are no
sessions currently available in the pool this waits for the specified number of seconds.
Whilst it is waiting other threads are allowed to run and if a session is returned to the pool it
will be used by the waiting method. At the end of the time period NULL is returned if no
session has become available. Note that this waiting time period should be treated as
approximate.

217

Chapter 7SQL Programming

Diagnosing Problems
As of Omnis Studio 5.0, the session object provides the $debugfile and $debuglevel
properties. These are useful in the event of program faults, if you are looking to optimise
network traffic or if you are simply curious about how the DAM is executing commands. It
should be noted that when debugging is enabled, there is a noticeable impact on
performance. Hence, debugging should be reserved for application development and
technical support issues- in which case use of $debuglevel 4 is recommended.
When $debugfile is set to a valid filename, the DAM starts writing debug information to
this file- which is cleared before use. The file is created if it does not already exist.
Debugging continues either until the session object is destructed or until $debugfile is set to
an empty string. For Mac and Linux, a POSIX style path is expected and the user must have
permission to write to the file at the specified location.
It is also possible to assign the value stderr to $debugfile. This is useful for Mac and
Linux platforms where Omnis is run from the command prompt. Debug information will be
written to the terminal window.
The $debuglevel property determines the level of debugging information that is written to
the debug file and supports the following values:

218

No debugging. The debug file remains open but debugging output is


suspended until $debuglevel is set to a higher level.

Base level debugging. At this level, the DAM base class writes high level
descriptions about the operation of the DAM; statement prepares, executes,
describing of result sets, fetching, etc. This is the default level of debugging.

Detail refinement 1. At this level metadata, property and method call


information are also written including the SQL text associated with
$prepare()s and $execdirect()s.

Detail refinement 2. At this level, buffer allocation, parameter and bind


variable values are also written where possible.

Detail refinement 3. At this level, details of parameters passed to


implementation API calls are also written, provided that the DAM
implements this level of debugging.

Session and Statement Properties and Methods

Session and Statement Properties and


Methods
Below is a summary of the base methods and properties common to all object DAMs.
For details of DAM specific methods and properties, refer to the chapter on Server Specific
Programming.

Session Methods
Method

Description

$begin()

$begin() explicitly begins a new database transaction.

$clear()

$clear() clears all statement objects based in the session and


resets the session to its default state.

$coltext

$coltext(vVarRef) returns the DBMS specific SQL text


corresponding to the data-type of the supplied variable.

$commit()

$commit() explicitly commits the current database transaction.

$createnames()

$createnames(vTableDef,[bNullInfo,bPrimaryKeyInfo]) returns
a DBMS specific text string consisting of the SQL column names
and types based on the column types of the supplied list or row
variable. The optional parameters bNullInfo and
bPrimaryKeyInfo can be used to request additional information
about columns where the list has been defined from a schema or
file class.

$insertnames()

$insertnames(wRowRef) returns a text string consisting the SQL


column names and bind variable names corresponding to the
supplied list or row variable.

$logoff()

$logoff() disconnects the session from the database.

$logon()

$logon(cHostname,cUsername,cPassword[,cSessionName])
connects the session to the DBMS using the supplied parameters,
The optional cSessionName parameter registers the session with
$root.$sessions and the SQL Browser utility.

$makeschema()

$makeschema(pSchema,cTableName) makes a schema class


based on the specified server table name.

$newstatement()

$newstatement([cStatementname]) returns an instance to a new


statement object. cStatementname is optional.

$newstatementref()

$newstatementref([cStatementname]) returns a reference to a


new statement object. cStatementname is optional.

$nextnativeerror()

$nextnativeerror() retrieves a pending DBMS error code and

219

Chapter 7SQL Programming


Method

Description
error message, placing them in $nativeerrorcode and
$nativeerrortext.

220

$rollback()

$rollback() explicitly rolls-back the current database transaction.

$rpcdefine()

$rpcdefine(cProcedureName,lParamList) defines the parameter


structure for a subsequent call to statement.$rpc(). The definition
and contents of the lParamList parameter are discussed in
Calling a Remote Procedure

$selectnames()

$selectnames(vTableDef[,cTableName]) returns a text string


consisting of comma delimited column names corresponding to
vTableDef. The optional cTableName is pre-pended to the
column names if supplied.

$updatenames()

$updatenames(wRowRef) returns the text string for a SQL


UPDATE clause based on the contents of wRowRef.

$wherenames()

$wherenames(wRowRef[,cTableName,cComparison,cOperator])
returns the text string for a SQL WHERE clause based on the
supplied list or row variable. The optional cTableName is prepended to the column names if supplied. The cComparison and
cOperator parameters can be used to modify the corresponding
parts of the WHERE clause.

Session and Statement Properties and Methods

Session Properties
Property

Description

$allowstransactions

kTrue if the session is capable of manual transactions. (Readonly)

$apiversion

Version of the database client API that the DAM was built with.
(Read-only)

$autobegintran

kTrue if the session automatically begins transactions, e.g. each


time a transaction is committed/rolled-back. In which case,
$begin() should not be used. (Read-only)

$blobsize

The maximum size of a binary data item. Default value 10MB.


Also used by $createnames() for some DBMSs.

$charmap

Determines how character data received from and sent to the


DBMS is mapped. For Non-Unicode session objects, this
property accepts values of kSessionCharMapOmnis (the
default), kSessionCharMapNative or kSessionCharMapTable.
For Unicode session objects, this property governs the character
set assumed for fetched 8-bit data; either kSessionCharMapLatin
or kSessionCharMapRoman.

$commitmode

Indicates how SQL cursors behave when a session is committed.


Either kSessionCommitClose, kSessionCommitDelete or
kSessionCommitPreserve. (Read-only)

$damname

The DAM name as shown in $root.$components. (Read-only)

$debugfile

When set to a valid filename, the DAM starts writing debug


information to this file. Debugging continues either until the
session object is destructed or until $debugfile is set to an empty
string. For Mac and Linux, a POSIX style path is expected.

$debuglevel

Determines the level of debugging information that is written to


the $debugfile. 0 specifies no debugging, 4 specifies maximum
debugging info.

$defaultdate

Used to specify the default date parts to be used when parts of


the date are omitted at bind time. The default value for this
property is 1 Jan 2000 00:00:00

$emptydateisnull

If set to kTrue, all out-going bound dates with an empty value


will be set to NULL.

$encoding

Indicates the Unicode encoding used by the client library for


bind data and fetched rows. The DAM converts to and from this
encoding when exchanging data with Omnis. (Read-only)

$codepage

Set to one of the kUniType constants found in the Catalog


under Unicode types. Default value kUniTypeAnsiLatin1. This

221

Chapter 7SQL Programming


Property

Description
property determines the ANSI code page used to interpret nonUnicode data. $codepage should match the character set of the
database so that non-Unicode extended characters are read and
written correctly.

222

$errorcode

Returns the Internal Omnis error code generated by last


executed session method. (Read-only)

$errortext

Returns the error message generated by the last executed session


method. (Read-only)

$fetch64bitints

If kTrue (default), 64-bit integers are fetched into 64-bit Integer


fields. If kFalse, they are fetched as 32-bit Integers and
truncated accordingly. This property provides backward
compatibility with the old-style web client plug-in which does
not support 64-bit integers.

$hostname

The hostname currently in use by the connection. (read-only)

$lobchunksize

The size (in bytes) of a single chunk when inserting large binary
data. Default value is 32KB

$lobthreshold

The size (in bytes) of a binary data item at or above which


chunking will occur. Default value is 32KB

$maptable

The path to the character map files to use when $charmap is


assigned kSessionCharMapTable. The filename is specified
without either the .in or .out suffix.

$nativeerrorcode

The error code generated by the DBMS or DBMS clientware in


response to the last executed session method. (Read-only)

$nativeerrorpending

kTrue indicates that a further native error code and error text are
available. See session.$nextnativeerror().(Read-only)

$nativeerrortext

The error message generated by the DBMS or DBMS clientware


in response to the last executed session method. (Read-only)

$password

The password currently in use by the connection. (Read-only)

$quotedidentifier

If kTrue, table and column name identifiers returned from the


$createnames(), $insertnames(), $updatenames(), $selectnames()
and $wherenames() methods will be quoted thus, facilitating
case-sensitive names and names containing spaces. Affects table
instance methods as well as session object methods. (Studio 5.2
and later)

$rollbackmode

Indicates how SQL cursors behave when a session is rolledback. Either kSessionRollbackClose, kSessionRollbackDelete or
kSessionRollbackPreserve. (Read-only)

$sqldecimalseperator

The character that the DBMS uses to represent the decimal

Session and Statement Properties and Methods


Property

Description
separator when storing numeric values, usually .

$sqlstripspaces

If kTrue, trailing blank characters are stripped from character


data returned from the DBMS.

$sqlthousandsseperator

The character that the DBMS uses to represent the thousands


separator when storing numeric values, usually ,

$state

Indicates the current state of the session objects connection.


Either kSessionStateLoggedOff or kSessionStateLoggedOn.
(Read-only)

$transactionmode

Used to set the transaction mode. Can be one of


kSessionTranAutomatic (the default), kSessionTranManual or
kSessionTranServer.

$unicode

Used to enable/disable 8-bit compatibility mode.


If kTrue (the default), all character data is exchanged with the
client as Unicode. If kFalse, the behaviour of a non-Unicode
DAM is adopted.

$username

The username currently in use by the connection. (Read-only)

$validateutf8

If kTrue and the $encoding is kSessionEncodingUtf8 and


$unicode is kTrue, fetched UTF-8 data is validated and treated
as non-Unicode data on failure.
See also; $charmap. Not implemented by all DAMs.

$version

Once a session has been established this is the version of the


database the object is connected to. This defaults after a
$logoff(). (Read-only)

223

Chapter 7SQL Programming

Statement Methods

224

Method

Description

$clear()

$clear() clears pending results and resets the statement.

$columns()

$columns(cTableName) generates a result set describing the


columns of the specified table.

$execdirect()

$execdirect([cSqlText]) directly executes the specified SQL text


or executes the contents of the Statement buffer if cSqlText is
omitted.

$execute()

$execute() executes previously prepared SQL text.

$fetch()

$fetch([lListOrRow,iRowCount,bAppend]) fetches the specified


number of rows from the result set into the supplied list variable.
If iRowCount is omitted, a single row is fetched. If bAppend is
kFalse or omitted, the list or row contents are cleared prior to the
fetch.

$fetchinto()

$fetchinto(vParam1vParamN) fetches one row of the result set


and stores each column in the supplied variables, one variable for
each column.

$fetchtofile()

$fetchtofile(cFileName[,iRowCount,bAppend,bColumnNames])
fetches the specified number of rows from the result set and stores
them in the specified file. iRowCount, bAppend and
bColumnNames parameters are optional.

$indexes()

$indexes(cTableName[,iIndexType]) generates a result set


providing information on the indexes of the specified table. The
optional iIndexType can be one of kStatementIndexUnique
(default), kStatementIndexNonUnique or kStatementIndexAll.

$nextnativeerror()

$nextnativeerror() retrieves a pending DBMS error code and error


message for the statement object, placing them in $nativeerrorcode
and $nativeerrortext.

$prepare()

$prepare([cSqlText]) prepares the supplied SQL text ready for


subsequent execution. If omitted, the contents of the statement
buffer are prepared instead.

$results()

$results(lListOrRow) populates the supplied list variable with a


description of the columns contained in the current result set.

$rpc()

$rpc(cRpcName,vParam1vParamN) calls the specified remote


procedure. Any supplied parameters are passed to the procedure
call.

$rpcparameters()

$rpcparameters(cRpcName) generates a result set describing the


parameters used by the specified remote procedure.

Session and Statement Properties and Methods


Method

Description

$rpcprocedures()

$rpcprocedures([cOwnerName]) generates a result set containing


the names of remote procedures callable by the specified user. If
omitted, all procedure names are returned.

$tables()

$tables([iTableType,cTableOwner]) generates a result set


containing the names of tables accessible by the specified user. If
cTableOwner is omitted all tables are returned. iTableType can be
one of kStatementServerTable, kStatementServerView or
kStatementServerAll (the default).

Statement Properties
Property

Description

$batchsize

The number of simultaneous rows to be retrieved for a single


network transaction . Defaults to 1 but accepts any long integer
value. Not implemented by all DBMSs, in which case this
property will be read-only.

$effectivebatchsize

Reflects the maximum attainable batchsize for the current


statement. Will be less than $batchsize if memory for the
desired batch size cannot be accommodated. (equivalent to
$maxbuffersize / largest-column-size) (Read-only)

$columncount

The number of columns contained in the current result set.


(Read-only)

$columndelimiter

The character used to delimit column values when fetching


data using $fetchtofile(). Defaults to kTab but accepts any
single character value. Non-printable characters should be
assigned using the chr() function.

$errorcode

The Omnis internal error code generated by the last statement


method. (Read-only)

$errortext

The error message generated by the last statement method.


(Read-only)

$maxbuffersize

Used in conjunction with $batchsize. Sets the maximum buffer


size used to store an array of column values when batch
fetching. Defaults to 32KB but accepts any value larger than
255. Not implemented by all DBMSs, in which case this
property will be read-only.

$nativeerrorcode

Error code generated by the last statement method. (Readonly)

$nativeerrorpending

Indicates that a further error message is available. Use


$nextnativeerror() to retrieve. (Read-only)

225

Chapter 7SQL Programming

226

Property

Description

$nativeerrortext

Error message generated by the last statement method. (Readonly)

$resultspending

Indicates that the last statement method generated some results


or that there is another result set pending. (Read-only)

$rowcount

The number of rows in the current result set. If a particular


session object cannot determine this value, this property
returns 1. (Read-only)

$rowdelimiter

The character used to delimit row values when fetching data


using $fetchtofile(). Defaults to kCr but accepts any single
character value. Non-printable characters should be assigned
using the chr() function.

$rowsaffected

The number of rows affected by the last executed statement;


usually an INSERT, UPDATE or DELETE statement. If a
particular session object cannot determine this value, this
property returns 1. (Read-only)

$rowsfetched

The number of rows retrieved by the last fetch method to be


executed. (Read-only)

$rpcreturnvalue

The return value of the most recently executed call to


$rpc().(Read-only)

$state

A constant value indicating the current state of the statement


object. (Read-only)

$statementname

The name which was assigned to the statement object during


creation. (Read-only)

$sqlstripspaces

Denotes that fetched character data should have trailing spaces


stripped.

$sqltext

The DBMS representation of the last SQL statement submitted


to $prepare() or $execdirect(). (Read-only)

$usecursor

Denotes that this statement object should be associated with a


SQL cursor.

SQL Multi-tasking and SQL Workers

SQL Multi-tasking and SQL Workers


You can execute long-running tasks such as a SELECT statement on a separate background
thread that reports back to the main thread as each task completes. To enable this
functionality, the Omnis DAMs allow the creation of SQL Workers which are instantiated
from a new SQL Object variable type available in the Oracle, ODBC, JDBC, MySQL,
PostgreSQL, DB2, Sybase, and SQLite DAMs.
SQL Worker object completion methods allow list fields and other form data to be
populated asynchronously, making applications more responsive and potentially faster
where multiple SQL Workers are used.

Overview
The SQL Worker Objects support three primary methods:
$init()
Initializes or resets a worker object ready to perform its task
$start()
Starts the worker task on a background thread (non-blocking)
$cancel()
Aborts a worker task running on a background thread
There are additional properties to allow a running task to be discarded in place of a new
task and to cancel such tasks as they become orphaned. There is also a property to report
the state of a worker object's running background thread.
Worker objects are created by sub-classing an Omnis Object class with the appropriate SQL
Worker Object type. You initialize the object by supplying a SQL statement along with any
bind variables that the SQL statement may need. Logon details or optionally the name of a
session pool are also passed during initialization.
A SQL Worker thread is dispatched by calling $start(). Upon completion, the worker thread
calls back into the worker object's $completed() method, or $cancelled(), with the result set
or error information.

227

Chapter 7SQL Programming

SQL Worker Object Methods


Method

Description

$init()

$init(ParamRow). Initializes or resets a worker object ready to perform


a unit of work.*

$start()

Starts the worker task running on a background thread (non-blocking).*

$run()

Starts the worker task running on the caller thread (blocks until
complete). Intended for testing purposes.*

$cancel()

Aborts a worker task running on a background thread.*

$sessionref()

$sessionref(ObjectRef). Returns a reference to the session object being


used by the underlying Worker Delegate.*

$completed()

Called by the Worker Delegate upon completion of its work.

$cancelled()

Called by the Worker Delegate if the running background task was


cancelled.

*Returns kTrue on successful execution, kFalse otherwise.

SQL Worker Object Properties

228

Property

Description

$cancelifrunning

If kFalse (the default), orphaned background tasks run to


completion. If kTrue, they are instructed to cancel before being
detached.

$waitforcomplete

If kTrue (the default), the Interface Object waits for completion of


a running background task before the object can be used again. If
kFalse, the running task is detached and a new Worker Delegate
takes its place.

$state

Returns the current state of the underlying background task; either


kWorkerStateCancelled, kWorkerStateClear,
kWorkerStateComplete, kWorkerStateError or
kWorkerStateRunning.

$errorcode

On failure of a command function, contains the error code.

$errortext

On failure of a command function, contains the error message.

$threadcount

Reports the number of worker threads currently being monitored


by the underlying Thread Timer object.

SQL Multi-tasking and SQL Workers

Creating SQL Worker Objects


Worker objects are created by sub-classing an Omnis object class as a Worker Object. For
example, using the Select Object dialog, assigning a $superclass for use with an Oracle
connection results in: .ORACLE8DAM.Worker Objects\OracleWorker.

To access worker functionality from your code, you then create one or more object instance
variables of subtype <your-object >.

Worker Object Initialization


A worker object must be initialized on the caller thread before it can run. You initialize the
object by supplying a SQL statement along with any bind variables that the SQL statement
may require. Logon details or optionally- the name of a session pool are also passed during
initialization.
The initialization parameters are supplied to the $init() method via a row containing
attribute values. Attribute names appear in the column headings. The attribute names
recognized by the Worker Object are as follows (case-insensitive):

229

Chapter 7SQL Programming


Attribute name

Attribute value

session

A session object or object reference. The session must be logged-on


and in a useable state.

poolname

The name of an existing session pool. The worker will take a session
object from this pool, returning it upon completion.

hostname

The hostname/IP address of the database server.

database

The database name to use for a logon.

username

The username to use for a logon.

password

The password to use for a logon.

query

The SQL statement to be executed by the worker object.

bindvars

A list containing bind variable values. Bind variables are read in


column order. If the list contains multiple rows, the query is reexecuted for each row.

If the session attribute is supplied, the other logon attributes, i.e. hostname, database,
username & password are ignored, since it is assumed that the session object is already in a
useable state. Please Note: In this mode, the session should be considered reserved for use
exclusively by the worker. If the main application attempts to share a session object being
used by a worker running on another thread, the results are undefined.
The logon parameters are also ignored if the poolname attribute is supplied. In this mode,
the worker attempts to obtain a session from the named session pool, releasing it when the
worker task completes. (If both session and poolname are supplied, poolname is ignored.)
Where neither, session or poolname are supplied, an internal session object is created
dynamically. Valid logon credentials should be supplied via hostname, username and
password. Although read during the call to $init(), the worker will not attempt to logon until
the $run() or $start() method is called. In this mode, the session is automatically logged-off
when the worker task completes (or is cancelled). Should you need to modify one or more
session attributes before calling $run() or $start(), it is possible to obtain a reference to the
session object by calling the worker objects $sessionref() method, for example:
Do iWorkerObj.$sessionref(lObjRef) Returns #F
Do lObjRef.$port.$assign(5435)

The SQL text supplied via the query attribute may contain any SQL statement but ideally,
should be a statement that normally takes an appreciable amount of time to execute, for
example; a SELECT, UPDATE or DELETE statement. The query text may also contain one
or more bind variables, specified using standard @[] notation.
Bind variable values are supplied via a separate bindvars parameter. The supplied list is
stored during $init() and read when the worker task starts. Where the list contains multiple
rows, the worker re-executes the supplied SQL statement for each row of bind variables.

230

SQL Multi-tasking and SQL Workers


Note that the worker ignores any variable names specified in the SQL text; only the place
markers are used when identifying the bind variable positions.

Running the Worker Object


The $start() method causes the worker task to run on a background thread. Thus, return
from $start() is immediate and the main application is free to continue processing. For
example, the iWorkerObj var has been created from the oPostgreSQLWorker class:

;; iWorkerObj is an instance of an Object class


Calculate Params as row(
iSQLText,'192.168. 0.10,iUser,iPassword,iDBName)
Do Params.$redefine(query,hostname,username,password,database)
Do iWorkerObj.$init(Params)
Do iWorkerObj.$start() Returns #F

The $run() method is analogous to $start() but provided for debugging and testing purposes
only. In this mode, the benefit of the worker object is negated owing to the fact that the
worker will run on the same thread as the caller, thus blocking the caller thread until the
worker task is complete.
Once initialized, a worker object may be run repeatedly if desired provided that the supplied
session object remains useable, the session pool has one or more free sessions or that the
logon credentials remain valid. Any bind variables supplied will be re-used each time the
worker is run.
If an error occurs during $init(), $start() or $run(), an error message is returned via the
objects $errorcode and $errortext properties.

Processing Worker Results


When complete, the worker task causes the main thread to jump into one of the worker
objects callback methods:
$completed()
This method is called with a row parameter defined with two columns: Results: a
single-column list containing zero or more SQL result sets (lists). Errors: a two-column
list containing ErrorCode and ErrorMsg values.
$cancelled()
This method is called (without parameters)if the user calls $cancel() on the worker
object whilst it is running. When cancelled, any pending results are discarded.
A library may contain multiple worker objects of a given type. Each may be assigned a
separate unit of work (SQL query) and each may be started asynchronously. It is the
responsibility of the completion method in each worker object to process its result

231

Chapter 7SQL Programming


information and make this available to the main application as/when it becomes available.
For example, here is a $completed() method:
Calculate List as pRow.Results.1.1 ;;extract the first result set
Calculate Errors as pRow.Errors ;;extract list containing error info
If Errors.$linecount()>0
Do method reportError(Errors)
Else
Do method updateWindow(List) ;; see comment below
End If
Calculate iThreadCount as $cinst.$threadCount ;;shows how many
threads are running

If the results returned by $completed() are to be displayed in a window or a remote form in


the JavaScript Client, you will have to explicitly redraw the window instance, or in the case
of a web form the remote client must contact the server to get updated automatically.

Worker State
The current state of a SQL Worker object may be interrogated by inspecting the objects
$state property. This will return either:
kWorkerStateCancelled The worker has been cancelled.
kWorkerStateClear The worker has been initialized.
kWorkerStateComplete The worker has completed.
kWorkerStateError An error occurred (see $errortext).
kWorkerStateRunning The worker is currently running.
For example:
If iWorkerObj.$state=kWorkerStateRunning & iWorkerObj
.$waitforcomplete=kTrue
Calculate iMesg as 'Still running (waiting for completion)'
Quit method
End If

How SQL Worker Objects work


A worker object may be thought of as three sub-objects:
Interface Object
This takes the form of a standard Omnis non-visual object and provides the methods
and properties described above
Worker Delegate Object
Normally created/executed on a background thread, the Worker Delegate performs the
actual work of the worker object, calling back to the Interface Object upon completion.
232

SQL Multi-tasking and SQL Workers


Thread Timer Object
Declared statically, each Worker Delegate subscribes to the Thread Timer object
when it starts. Thread Timer polls all worker threads of a given type, prompting them to
call back to their corresponding Interface Objects upon completion.

Behind each Worker Object, there are hidden Worker Delegate and Thread Timer objects.

Detaching Worker Processes


When instructed to $start(), the Worker Delegate completes its work before calling back to
the Interface Objects $completed() or $cancelled() method. For $run(), $completed() is
always called since the worker object blocks- preventing cancellation.
For $start() however, the Interface Object may legitimately go out-of-scope or otherwise get
destructed before the worker thread completes. In this situation, the worker thread has no
object and hence no $completed()/$cancelled() method to call back to. Any results or error
information will therefore be discarded.

A detached Worker Delegate. The Interface Object may have gone out-of-scope or may now point to a
new delegate.

Upon destruction of an Interface Object, the object transfers ownership of the worker
delegate to the Thread Timer object. One Thread Timer object monitors all Worker objects
of a given type and deletes any orphaned worker processes it owns upon completion.

233

Chapter 7SQL Programming

A single Thread Timer object monitors all Worker Delegates of a given type. An Interface Object can
initiate and receive results from a single Worker Delegate but there can be multiple Interface Objects.

Discarding Running Processes


In the case where the Interface Object remains in scope, it is possible to call $init() and
$start() whilst the worker object is still running a previous task. In this case, the
$waitforcomplete property determines whether the running process should be allowed to run
to completion and call back to the Interface Object to signal completion.
If $waitforcomplete is kFalse, the running process is detached from the Interface Object as
if the Interface Object were about to go out-of-scope. In this case however, a new Worker
Delegate object is created which is then used to execute the new worker process and
potentially call back to the Interface Object when complete.
If $waitforcomplete is kTrue, Worker Main returns an error to the Interface Object if an
attempt is made to re-use the worker object while the Worker Delegate is still running. In
this case, the worker object cannot be re-used until $completed()/$cancelled() has been
called and the $state changes to indicate completion.
A worker object with its $waitforcomplete property set to kFalse, effectively becomes a
fire and forget worker object, for example allowing a succession of INSERT, UPDATE
or DELETE statements to be continuously dispatched to separate threads using the same
worker object.

Cancelling Detached Processes


By default, orphaned worker threads are allowed to run to completion. When a worker
process becomes orphaned it may be preferable to issue a cancel request to the worker,
especially where it may be processing a SELECT statement- for which the results will not
be retrievable once detached from the Interface Object. This is achieved by setting
$cancelifrunning to kTrue before the worker object gets re-used or destructed.

234

SQL Multi-tasking and SQL Workers


If $cancelifrunning is set to kFalse (the default), orphaned worker threads run to completion
before discarding their results and being destructed by the Thread Timer object.

235

Chapter 8SQL Classes and Notation

Chapter 8SQL Classes


and Notation
Omnis has three SQL classes that provide the interface to your server database: they are the
schema, query, and table class. Schema and query classes map the structure of your server
database. They do not contain methods, and you cannot create instances of schema or query
classes. You can however use a schema or query class as the definition for an Omnis list
using the $definefromsqlclass() method, which lets you process your server data using the
SQL methods against your list. When you create a list based on a schema or query class a
table instance is created which contains the default SQL methods.
Table classes provide the interface to the data modeled by a schema or query class, and
exist primarily to allow you to override the default methods in the table instance. Like
schema and query classes, you can use a table class as the definition for an Omnis list and
use the same SQL methods against your list.
The SQL list methods and notation are described in this chapter. Creating SQL classes in
the Studio Browser is described in the Creating Web & Mobile Apps manual.

Schema Classes
A schema class maps the structure or data dictionary of a server table or view within your
library. A schema class contains the name of the server table or view, a list of column names
and data types, and some additional information about each column. The data types are the
equivalent Omnis data types, and the names must conform to the conventions used by the
particular server. Schema classes do not contain methods, and you cannot create instances
of a schema class. You can define a list based on a schema class using the Define list from
SQL class command or the $definefromsqlclass() method. You can create a schema class
using the New Class>>Schema option in the Studio Browser.

Schema Class Notation


Each library has a $schemas group containing all the schema classes in the library. A
schema class has the type kSchema.
In addition to the standard class properties, such as $moddate and $createdate, a schema
class has the following properties
$objs
the group of columns in the schema class
236

Schema Classes
$servertablename
the name of the server table or view to which the schema corresponds
The $objs group containing the columns in the schema class supports the group methods
including $first(), $add(), $addafter(), $addbefore(), and $remove(). The $add... methods
require the following parameters
Name
the name of the column
Type
constant representing the Omnis data type of the column
Subtype
constant representing the data subtype of the column
Description (optional)
a text string describing the column
Primary-key (optional)
a boolean set to kTrue if this column is a primary key. If omitted it defaults to kFalse
Maximum-Length (optional)
for character and national columns, the maximum length; for other types, Omnis
ignores the value of this parameter. If omitted for character and national columns, it
defaults to 10000000.
No-nulls (optional)
a boolean set to kTrue if this column cannot have NULL values. If omitted it defaults to
kFalse
You can identify a particular column in the $objs group using its column name, order, or
ident, a unique number within the scope of the schema class assigned to the column when
you add it. A schema column has the following properties (all are assignable except $ident)
$name
the name of the column
$coltype
the Omnis data type of the column
$colsubtype
the Omnis subtype for the data type of the column
$colsublen
the maximum length for Character and National columns
$desc
a text string describing the column
$primarykey
if kTrue the column is a primary key
237

Chapter 8SQL Classes and Notation


$nonull
if kTrue the column does not allow null values
$order
the position of the column in the list of columns in the schema class
$ident
a unique number within the scope of the schema class, identifying the column

List/Row subtypes
A schema class (or a query or table class) can be used as the subtype of a list or row
variable, that is, a class, instance, local, task or parameter variable, or a column in a list or
row defined from a SQL class.
Schema classes have a property $createinstancewhensubtype that controls whether or not
there is a table instance associated with a List or Row variable with a schema class as its
subtype. You can set this property in the Property Manager when editing the schema class:
it defaults to kTrue for existing and newly created schema classes.

Make Schema from Server Table


You can also create a schema using the Make schema from server table command. For
example
Describe server table (Columns) {ServerTable}
Make schema from server table {MySchema}

will create the schema MySchema, referencing server table ServerTable, using the current
Omnis session.

Query Classes
Query classes let you combine one or more schema classes or individual columns from one
or more schemas, to give you an application view of your server database. A query class
contains references to schema classes or individual schema columns. Like schema classes,
query classes do not contain methods, and you cannot create instances of a query class. You
can define a list based on a query class using the Define list from SQL class command or the
$definefromsqlclass() method.
You can create a query class using the New Class>>Query option in the Studio Browser.
The Catalog pops up when you open the query class editor, which lets you double-click on
schema class or column names to enter them into the query editor. Alternatively, you can
drag schema class or column names into the query editor. Furthermore, you can reorder
columns by dragging and dropping in the fixed left column of the query editor, and you can
drag columns from one query class onto another. You can also drag a column from the
schema editor to the query editor.
238

Query Classes
You can drag from the query list, the schema editor, and the Catalog, and drop onto the
extra query text field labeled Text appended to queries. Dragging a query column from the
right-hand list of the catalog query tab inserts a bind variable reference in the form
@[$cinst.name].
The column entries have a context menu, which allows you to delete a column, and to open
the schema editor for the schema containing the column.
The additional query text edit field has a context menu which allows you to insert text
commonly used in SQL queries.
The query class editor does not validate schema class or column names, nor does Omnis
automatically update query classes when you edit a schema class. You need to update your
SQL classes manually using the Find and Replace tool.
The alias allows you to eliminate duplicate column names when defining a list from the
query class. By default, each list column name is the same as the schema column name. You
can override this with the alias. If the column name is empty, meaning use all columns in the
schema, Omnis inserts the alias at the start of each column name in the schema, to create the
list column name; otherwise, Omnis uses a non-empty alias as the list column name.

Calculated Columns
Query classes can also contain calculated columns. A calculated column is an entry in a
query class which has:
A schema name, which determines the table to be used in the SQL statement.
A column name. This is the calculation. Omnis treats a column name as a calculation if
it contains at least one open parenthesis and one close parenthesis. This rule helps to
distinguish a calculated column from a badly named schema column. Omnis performs
no validation on the calculation, and it simply inserts it into queries generated by
$select or $selectdistinct, and into the result of $selectnames.
An alias, used as the list column name.
A calculated column is represented, in the list or row variable defined from a SQL class, as
a character column of maximum length. If you include strings in the form <schema
name>. or <library>.<schema name>. in the calculation, then Omnis replaces them with
<server table name>. when it adds the calculation to a query. The <server table name>
comes from the schema class.

Query Class Notation


Each library has the group $queries containing all the query classes in the library. A query
class has the type kQuery.
A query class has the standard properties of a class together with $extraquerytext, a text
string which in some cases Omnis appends to automatically generated SQL, and for
239

Chapter 8SQL Classes and Notation


example may contain a where clause. The extra query text string can be empty. Before
Omnis adds $extraquerytext to a SQL query, it replaces strings in the form <schema
name>. and <library>.<schema name>. with <server table name>.. The <server table
name> comes from the schema class. This allows you to design query classes which are
independent of the table names actually used on the server, since the only place storing the
table name is the schema.
A query class has a $objs group containing a list of references to schema columns, or
schema classes. $objs supports the same group methods as $objs for the schema class, with
the exception of $findname. The $add methods require the following parameters:
Schema name
the name of the schema, which can be qualified by a library name
Column name (optional)
the name of the column in the schema
Alias (optional)
the alias used to eliminate duplicate list column names
Each query class object has the following properties.
$schema
the name of the schema, which can be qualified by a library name
$colname
the name of the column in the schema; if empty, all columns from the schema class
specified in the $schema property are included
$alias
lets you eliminate duplicate column names from a list defined from a query or a table
class referencing the query; if $colname is empty, this is a prefix which Omnis inserts at
the start of each column name in the schema named in $schema; otherwise, Omnis uses
a non-empty alias in the place of the column name
$order
the position of the object in the class
$ident
a unique numeric identifier for the object
A list defined from a query class using the $definefromsqlclass() method has columns which
correspond to the objects in the query class. The order of the columns in the list corresponds
to the order of the columns in the query class. When an object includes a complete schema,
the columns have the order of the columns in the schema class. You can eliminate duplicate
list column names using the $alias property.

240

Creating Server Tables from Schema or Query


Classes

Queries Tab in the Catalog


The Catalog has a queries tab which lists the query classes in the current library. For each
query class, the right hand list shows the list column names which would result from
defining a list from the query class.

Creating Server Tables from Schema or


Query Classes
You can create a table or view in your server database by dragging a schema or query class
from your library in the Studio Browser and dropping it onto an open session in the SQL
Browser.
To create a server table or view from a schema or query class

Create the schema or query class in the Studio Browser

Define the columns in the schema or query class

Use the SQL Browser to open the SQL session for your database

Drag the schema or query class from your library and drop it on to your Session

If you drag a schema class onto an open session, Omnis creates a SQL table with the table
name defined in your schema class. If you drag a query class, Omnis creates a SQL view
with the name of the query class.

241

Chapter 8SQL Classes and Notation

Table Classes
An instance of a table class provides the interface to the data modeled by a schema or query
class. You only need to create a table class if you wish to override some of the default
processing provided by the built-in table instance methods.
You can create a table class using the New Class>>Table option in the Studio Browser. You
can edit the methods for a table class or add your own custom methods in the method editor.

Table Class Notation


Each library has a $tables group containing all the table classes in your library. A table class
has all the basic properties of a class plus $sqlclassname, which holds the name of the
schema or query class associated with the table class. To create a table class using a method,
you can use the $add() method.
Do $clib.$tables.$add(MyTable) Returns TabRef
; returns a reference to the new table
Do TabRef.$sqlclassname.$assign(AgentSchema) Returns MyFlag

Table Instances
You create a table instance in Omnis when you define a list or row variable from a schema,
query, or table class, using the Define list from SQL class command, or the
$definefromsqlclass() method. Table instances created from schema or query classes have
all the default methods of a table instance. Table instances created from a table class have
all the default methods of the table class in addition to any custom methods you have added,
perhaps to override the default methods.
When you use Define list from SQL class or $definefromsqlclass(), Omnis defines your list
to have either one column for each column in the schema class, or one column for each
column referenced by the query class (which can contain a subset of columns from a schema
class). In the case where you use a table class, Omnis uses the $sqlclassname property of the
table class to determine the schema or query from which to define the list. You can pass the
query/schema/table class as either an item reference to the class, or as the name of the class,
in the form [library.]class, where the library defaults to the current library if omitted.
A list variable defined in this way has all of the methods and properties of a normal list
variable, together with all of the methods and properties of the table instance. You never
access the table instance directly; you can think of it as being contained in the list variable.

242

Table Instances
For example, if you want to display a grid containing your data in a SQL form you can use
the following code in the $construct() method of the form to create a list based on a schema
class
; Declare instance variable iv_SQLData of type List
Set current session {session-name}
Do iv_SQLData.$definefromsqlclass('SCHEMACLASSNAME')
Do iv_SQLData.$select()
Do iv_SQLData.$fetch(1000) ;; Fetch up to 1000 rows

Once you have defined and built your list you can use the table instance methods to
manipulate the data. Equally you could declare a row variable, define it from a table,
schema or query class, and manipulate your data on a row-by-row basis using many of the
same methods.
The Define list from SQL class command and $definefromsqlclass() method both reset the
$linemax property of the list to its largest possible value.
If you pass a schema class, or a table class that references a schema class, then the list is
defined to have all columns in the schema, unless you pass an explicit list of columns to use
from the schema, such as:
Do iv_SQLData.$definefromsqlclass(query / schema / table class
[,cCol1,cCol2,...])

Passing Parameters to a Table instance


You can pass construction parameters to the $construct() method of the table instance by
adding a list of parameters after the list of columns in your list definition method, as
follows:
Do iv_SQLData.$definefromsqlclass(query/schema/table class
[,cCol1,cCol2,...] [,,cons-params])

Note that there is an empty parameter to separate the explicit column list from the consparams that are passed to $construct for the table instance. Note also that this empty
parameter is still required when using a query class or table class that references a query
class.

Adding Columns to a SQL List


You can add columns to a list which has a table instance using the $add() method. For
example, the following method defines a list from a query class and adds a column with the
specified definition to the right of the list.
Do LIST.$definefromsqlclass($clib.$queries.My_Query)
Do LIST.$cols.$add('MyCol',kCharacter,kSimplechar,1000)

243

Chapter 8SQL Classes and Notation


Columns added in this way are excluded from the SQL queries generated by the SQL
methods described in this section, since they are not defined in the SQL class. You can only
add columns to the right of the schema or query related columns in the list.

Table Instance Notation


Table instances have methods and properties which allow you to invoke SQL queries and
related functionality via the list containing the table instance. Some methods apply to list
variables only and some to row variables only. Some of these methods execute SQL, which
by default executes in the context of the current Omnis session. The methods do not manage
transactions; that is your responsibility.
The table instance methods are summarized in this section, with a more detailed description
of each method in the next section.
$select()
generates a Select statement and issues it to the server
$selectdistinct()
generates a Select DISTINCT statement and issues it to the server
$fetch()
for a list, fetches the next group of rows from the server, for a row, fetches the next row
The following methods apply to row variables only.
$insert()
inserts a row into the server database
$update()
updates a row (or rows if the where clause applies to several rows) in the server
database
$delete()
deletes a row (or rows if the where clause applies to several rows) from the server
database
The following methods apply to smart lists only, updating the server database from the list.
$doinserts()
inserts all rows in the list with the row status kRowInserted
$dodeletes()
deletes all rows in the list with the row status kRowDeleted
$doupdates()
updates all rows in the list with the row status kRowUpdated
$dowork()
executes the three $do... methods above, in the order delete, update, insert

244

Table Instances
When you call $doinserts(), $dodeletes(), $doupdates() or $dowork(), the table instance
calls the appropriate method(s) from the following list, to invoke each individual insert,
delete or update. This allows you to use table class methods to override the default
processing. As a consequence these methods only apply to smart lists.
$doinsert()
inserts a single row with row status kRowInserted
$dodelete()
deletes a single row with row status kRowDeleted
$doupdate()
updates a single row with row status kRowUpdated
The following methods apply to smart lists only, reverting the state of the list, that is, they
do not affect the server database.
$undoinserts()
removes any inserted rows from the list
$undodeletes()
restores any deleted rows to the list, and resets their status to kRowUnchanged
$undoupdates()
restores any updated rows to their original value, and resets their status to
kRowUnchanged
$undowork()
executes the three $undo... methods above, one after the other, in the order insert,
update, delete
You can use the following methods to create text strings suitable for using in SQL
statements. You are most likely to use these if you override default table instance methods
using a table class.
$selectnames()
returns a comma-separated list of column names in the list or row variable, suitable for
inclusion in a SELECT statement
$createname()
returns a comma-separated list of column names, data types, and the NULL or NOT
NULL status, for each column in the list or row variable, suitable for inclusion in a
CREATE TABLE statement
$updatenames()
returns a text string containing a SET clause, suitable for inclusion in an UPDATE
statement
$insertnames()
returns a text string containing a list of columns and values for a row variable, suitable
for inclusion in an INSERT statement
245

Chapter 8SQL Classes and Notation


$wherenames()
returns a text string containing a Where clause, suitable for inclusion in a SQL
statement that requires a constraining clause
You can use the following method in a table class.
$sqlerror()
a means of reporting errors. The table instance default methods call this method when a
problem occurs while executing SQL
Table instances have the properties of list or row variables as well as the following.
$sqlclassname
the name of the associated schema or query class used to define the columns of the list;
this property is NOT assignable
$useprimarykeys
if true, only those schema columns that have their $primarykey property set to true are
used in Where clauses for automatically generated Update and Delete statements.
Omnis automatically sets $useprimarykeys to kTrue when defining the list, if and only
if there is at least one primary key column in the list
$extraquerytext
a text string appended to automatically generated SQL; used by the $select(),
$selectdistinct(), $update(), $delete(), $doupdates() and $dodeletes() methods; for
example, it can contain a Where clause. When the table instance is defined either
directly or indirectly via a query class, Omnis sets the initial value of this property from
the query class; otherwise, this property is initially empty
$servertablenames
a comma-separated list of the names of the server tables or views referenced by the
schemas associated with the table instance. If the table instance uses a schema class to
define its columns, there is only one name in $servertablenames. If the table instance
uses a query class, there can be more than one name, corresponding to the schemas
referenced by the query class, and in the order that the schemas are first encountered in
the query class
$sessionname
the name of the Omnis session to the server, on which the table instance methods
execute their SQL; if empty, Omnis issues the SQL on the current session
$colsinset
the number of columns in the current result set for the session used by the table
instance; this property is NOT assignable
$rowsaffected
the number of rows affected by the last call to $insert(), $update(), $delete(),
$doinserts(), $doupdates(), or $dodeletes()

246

Table Instances
$rowsfetched
the number of rows fetched so far, using the $fetch() method, in the current result set
for the session used by the table instance
$allrowsfetched
set to kTrue when all rows in the current result set for the current table instance have
been fetched, otherwise kFalse at other times
List columns in a list containing a table instance have three table instance related properties:
$excludefromupdate, $excludefrominsert and $excludefromwhere.
When $excludefromupdate is true, the column is omitted from the result of $updatenames,
and from the list of columns in the SQL statements generated by $update.
When $excludefrominsert is true, the column is omitted from the result of $insertnames, and
from the list of columns in the SQL statements generated by $insert.
Note that $excludefromupdate does not cause the column to be omitted from the where
clause generated by $update and $updatenames, therefore allowing you to have a column
which is purely a key and not updated. If you do want to exclude a column from the where
clause, set $excludefromwhere to true. $excludefromwhere affects the where clause
generated by $update, $updatenames, $delete and $wherenames.
For example:
Do MyList.$cols.MyKey.$excludefromupdate.$assign(kTrue)

The default setting of these properties is kFalse, except for calculated columns, in which
case the default is kTrue. However, note that calculated columns are omitted from the where
clause, irrespective of the setting of $excludefromwhere.
If you define a list from a SQL class and use $add to add additional columns, you cannot set
these properties for the additional columns.

Table Instance Methods


The following methods use the list variable MyList or row variable MyRow which can be
based on a schema, query, or table class.

$select()
Do MyList.$select([parameter-list]) Returns STATUS

$select() generates a Select statement and issues it to the server. You can optionally pass
any number of parameters which Omnis concatenates into one text string. For example,
parameter-list could be a Where or Order By clause. The method returns kTrue if the table
instance successfully issued the Select.
The $select() method executes the SQL statement equivalent to
Select [$cinst.$selectnames()] from [$cinst.$servertablenames]
[$extraquerytext] [parameter-list]

247

Chapter 8SQL Classes and Notation


The following $construct() method for a SQL form defines a row variable and builds a
select table. The form contains an instance variable called iv_SQLData with type Row.
Set current session {session-name}
Do iv_SQLData.$definefromsqlclass('schema-name')
Do iv_SQLData.$select()

$selectdistinct()
Do MyList.$selectdistinct([parameter-list]) Returns STATUS

$selectdistinct() is identical in every way to $select(), except that it generates a Select


Distinct query.

$fetch()
Do MyList.$fetch(n[,append]) Returns STATUS

$fetch() fetches up to n rows of data from the server into the list, or for row variables
fetches the next row. If there are more rows available, a subsequent call to fetch will bring
them back, and so on. The $fetch() method returns a constant as follows
kFetchOk
kFetchFinished
kFetchError

Omnis fetched n rows into the list or row variable


Omnis fetched fewer than n rows into the variable; this means that there
are no more rows to fetch
an error occurred during the fetch; in this case, Omnis calls $sqlerror()
before returning from $fetch(), and the list contains any rows fetched
before the error occurred

When fetching into a list, if the Boolean append parameter is kTrue, Omnis appends the
fetched rows to those already in the list; otherwise, if append is kFalse, Omnis clears the list
before fetching the rows. If you omit the append parameter, it defaults to kFalse.
The following method implements a Next button on a SQL form using the $fetch() method
to fetch the next row of data. The form contains the instance variables iv_SQLData and
iv_OldRow both with type Row.
; declare local variable lv_Status of Long integer type
On evClick
Do iv_SQLData.$fetch() Returns lv_Status
If lv_Status=kFetchFinished|lv_Status=kFetchError
Do iv_SQLData.$select()
Do iv_SQLData.$fetch() Returns lv_Status
End If
Calculate iv_OldRow as iv_SQLData
Do $cwind.$redraw()

248

Table Instances

$insert()
Do MyRow.$insert() Returns STATUS

$insert() inserts the current data held in a row variable into the server database. It returns
kTrue if the table instance successfully issued the Insert. The $insert() method executes the
SQL statement equivalent to
Insert into [$cinst.$servertablenames] [$cinst.$insertnames()]

The following method implements an Insert button on a SQL form using the $insert()
method to insert the current value of the row variable. The form contains the instance
variable iv_SQLData with type Row.
On evClick
Do iv_SQLData.$insert()

;; inserts the current values

$update()
Do MyRow.$update(old_row[,disable_where]) Returns STATUS

$update() updates a row in a server table from the current data held in a row variable. It
returns kTrue if the table instance successfully issued the Update. Note that if the SQL
statement identifies more than one row, each row is updated.
The old_row parameter is a row variable containing the previous value of the row, prior to
the update.
The optional disable_where parameter is a boolean which defaults to kFalse when omitted.
If you pass kTrue, then Omnis excludes the where clause from the automatically generated
SQL. This may be useful if you want to pass your own where clause using $extraquerytext.
The $update() method executes the SQL statement equivalent to
Update [$cinst.$servertablenames][$cinst.$updatenames(old_row)]
[$extraquerytext]

The following method implements an Update button on a SQL form using the $update()
method. The form contains the instance variables iv_SQLData and iv_OldRow both with
type Row.
On evClick
Do iv_SQLData.$update(iv_OldRow)

$delete()
Do MyRow.$delete([disable_where]) Returns STATUS

$delete() deletes a row from a server table, matching that held in the row variable. It returns
kTrue if the table instance successfully issued the Delete. Note that if the SQL statement
identifies more than one row, each row is deleted. The optional disable_where parameter is
a boolean which defaults to kFalse when omitted. If you pass kTrue, then Omnis excludes
the where clause from the automatically generated SQL. This may be useful if you want to
pass your own where clause using $extraquerytext.
249

Chapter 8SQL Classes and Notation


The $delete() method executes the SQL statement equivalent to
Delete from [$cinst.$servertablenames] [$cinst.$wherenames()]
[$extraquerytext]

Note that [$cinst.$wherenames()] is omitted by setting disable_where to kTrue.


The following method implements a Delete button on a SQL form using the $delete()
method. The form contains the instance variable iv_SQLData with type Row.
On evClick
Do iv_SQLData.$delete()
Do iv_SQLData.$clear()
Do $cwind.$redraw()

$doinserts()
Do MyList.$doinserts()Returns MyFlag

This method only works for smart lists. $doinserts() inserts rows with status kRowInserted
in the history list, into the server table, and returns kTrue if the table instance successfully
issued the Inserts. $doinserts() calls $doinsert() once for each row to be inserted.
$doinserts() then accepts the changes to the smart list, unless an error occurred when doing
one of the Inserts.

$dodeletes()
Do MyList.$dodeletes([disable_where])Returns MyFlag

This method only works for smart lists. $dodeletes() deletes rows with status kRowDeleted
in the history list, from the server table, and returns kTrue if the table instance successfully
issued the Deletes. $dodeletes() calls $dodelete() once for each row to be deleted.
$dodeletes() then accepts the changes to the smart list, unless an error occurred when doing
one of the Deletes. The optional disable_where parameter is a boolean which defaults to
kFalse when omitted. If you pass kTrue, then Omnis excludes the where clause from the
automatically generated SQL. This may be useful if you want to pass your own where
clause using $extraquerytext.

$doupdates()
Do MyList.$doupdates([disable_where]) Returns MyFlag

This method only works for smart lists. $doupdates() updates rows with status
kRowUpdated in the history list, in the server table, and returns kTrue if the table instance
successfully issued the Updates. $doupdates() calls $doupdate() once for each row to be
updated. $doupdates() then accepts the changes to the smart list, unless an error occurred
when doing one of the Updates. The optional disable_where parameter is a boolean which
defaults to kFalse when omitted. If you pass kTrue, then Omnis excludes the where clause
from the automatically generated SQL. This may be useful if you want to pass your own
where clause using $extraquerytext.

250

Table Instances

$dowork()
Do MyList.$dowork([disable_where]) Returns MyFlag

This method only works for smart lists. $dowork() is a shorthand way to execute
$doupdates(), $dodeletes() and $doinserts(), and returns kTrue if the table instance
successfully completed the three operations. The optional disable_where parameter is a
boolean which defaults to kFalse when omitted. If you pass kTrue, then Omnis excludes the
where clause from the automatically generated SQL for $dodeletes() and $doupdates(). This
may be useful if you want to pass your own where clause using $extraquerytext.

$doinsert()
$doinsert(row)

$doinsert inserts the row into the server database. The default processing is equivalent to
row.$insert()

$dodelete()
$dodelete(row)

$dodelete deletes the row from the server database. The default processing is equivalent to
row.$delete()

$doupdate()
$doupdate(row,old_row)

$doupdate updates the row in the server database, using the old_row to locate the row. The
default processing is equivalent to
row.$update(old_row)

$undoinserts()
Do MyList.$undoinserts() Returns MyFlag

This method only works for smart lists. $undoinserts() undoes the Inserts to the list and
returns kTrue if successful. It is equivalent to the smart list method $revertlistinserts().

$undodeletes()
Do MyList.$undodeletes() Returns MyFlag

This method only works for smart lists. $ undodeletes() undoes the Deletes from the list and
returns kTrue if successful. It is equivalent to the smart list method $revertlistdeletes().

$undoupdates()
Do MyList.$undoupdates() Returns MyFlag

This method only works for smart lists. $undoupdates() undoes the Updates to the list and
returns kTrue if successful. It is equivalent to the smart list method $revertlistupdates().

251

Chapter 8SQL Classes and Notation

$undowork()
Do MyList.$undowork() Returns MyFlag

This method only works for smart lists. $undowork() undoes the changes to the list and
returns kTrue if successful. It is equivalent to the smart list method $revertlistwork().

$sqlerror()
Do MyList.$sqlerror(ERROR_TYPE, ERROR_CODE, ERROR_TEXT)

Omnis calls $sqlerror() when an error occurs while a default table instance method is
executing SQL. The default $sqlerror() method performs no processing, but you can
override it to provide your own SQL error handling. It passes the parameters:
ERROR_TYPE

ERROR_CODE
ERROR_TEXT

indicates the operation where the error occurred: kTableGeneralError,


kTableSelectError, kTableFetchError, kTableUpdateError,
kTableDeleteError or kTableInsertError.
contains the SQL error code, as returned by sys(131).
contains the SQL error text, as returned by sys(132).

$selectnames()
Do MyList.$selectnames() Returns SELECTTEXT

Returns a text string containing a comma-separated list of column names in the list variable
in the format:
TABLE.col1,TABLE.col2,TABLE.col3,...,TABLE.colN

The returned column names are the server column names of the list columns in the order
that they appear in the list, suitable for inclusion in a SELECT statement; also works for
row variables. Each column name is qualified with the name of the server table.

$createnames()
Do MyList.$createnames() Returns CREATETEXT

Returns a text string containing a comma-separated list of server column names and data
types for each column in the list variable, suitable for inclusion in a CREATE TABLE
statement; also works for row variables. The returned string is in the format:
col1 COLTYPE NULL/NOT NULL,col2 COLTYPE NULL/NOT NULL,
col3 COLTYPE NULL/NOT NULL,...,colN COLTYPE NULL/NOT NULL

The NULL or NOT NULL status of each column is derived from the $nonull property in the
underlying schema class defining the column.

252

Table Instances

$updatenames()
Do MyRow.$updatenames() Returns UPDATETEXT

Returns a text string in the format:


SET TABLE.col1=@[$cinst.col1],TABLE.col2=@[$cinst.col2],
TABLE.col3=@[$cinst.col3],...,TABLE.colN=@[$cinst.colN]

where col1coln are the server column names of the columns in the row variable. Each
column name is qualified with the name of the server table.
Do MyRow.$updatenames([old_name]) Returns UPDATETEXT

The optional parameter old_name is the name of a row variable to be used to generate a
where clause. If you include old_name, a where clause is concatenated to the returned
string in the following format:
WHERE col1=@[old_name.col1] AND ... AND colN=@[old_name.colN]

The columns in the where clause depend on the setting of $useprimarykeys. If


$useprimarykeys is kTrue, then the columns in the where clause are those columns marked
as primary keys in their schema class. Otherwise, the columns in the where clause are all
non-calculated columns except those with data type picture, list, row, binary or object.
You can replace $cinst in the returned string using:
Do MyRow.$updatenames([old_name][,row_name]) Returns UPDATETEXT

where row_name is the name of row variable which Omnis uses in the bind variables. This
may be useful if you override $doupdate() for a smart list.

$insertnames()
Do MyRow.$insertnames() Returns INSERTTEXT

Returns a text string with the format:


(TABLE.col1,TABLE.col2,TABLE.col3,...,TABLE.colN) VALUES
(@[$cinst.col1],@[$cinst.col2],@[$cinst.col3],...,@[$cinst.colN])

where col1...colN are the server column names of the columns in the row variable. The
initial column names in parentheses are qualified with the server table name. You can
replace $cinst in the returned string using:
Do MyRow.$insertnames([row_name]) Returns INSERTTEXT

where row_name is the name of row variable which Omnis uses in the bind variables. This
may be useful if you override $doinsert() for a smart list.

253

Chapter 8SQL Classes and Notation

$wherenames()
Do MyRow.$wherenames() Returns WHERETEXT

Returns a text string containing a Where clause in the format:


WHERE TABLE.col1=@[$cinst.col1] AND TABLE.col2=@[$cinst.col2] AND
TABLE.col3=@[$cinst.col3] AND ... TABLE.colN=@[$cinst.colN]

where col1...colN are the server column names of the columns in the row variable. Each
column name is qualified with the server table name.
The columns in the where clause depend on the setting of $useprimarykeys. If True, then
the columns in the where clause are those columns marked as primary keys in their schema
class. Otherwise, the columns in the where clause are all non-calculated columns except
those with data type picture, list, row, binary or object.
The = operator in the returned string is the default, but you can replace it with other
comparisons, such as < or >=, by passing them in the operator parameter.
Do MyRow.$wherenames([operator]) Returns WHERETEXT

You can replace $cinst in the returned string using:


Do MyRow.$wherenames([operator][,row_name]) Returns WHERETEXT

where row_name is the name of row variable which Omnis uses in the bind variables. This
may be useful if you override $dodelete() for a smart list.
If you want to see the SQL generated by the table instance SQL methods, you can use the
command Get SQL script to return the SQL to a character variable after you have executed
the SQL method. Note that the returned SQL will contain bind variable references which do
not contain $cinst. This is because Get SQL script does not execute in the same context as
the table instance. However, you will be able to see the SQL generated, which should help
you to debug problems.

SQL Classes and Sessions


A row or list variable defined from a SQL class has the $sessionobject property which is the
session object that is used by the table. For a new table instance $sessionobject is initially
empty. The $sessionobject may be assigned in the table class $construct method or
elsewhere. Here are some examples using a list variable iResultsList and object class
odbcobj
Do iResultsList.$definefromsqlclass('T_authors')
Do iResultsList.$sessionobject.$assign($objects.odbcobj.$new())
Do iResultsList.$sessionobject.$logon(hostname,username,password)

Or if a session pool is used:

254

SQL Classes and Sessions


Do iResultsList.$definefromsqlclass('T_authors')
Do iResultsList.$sessionobject.$assign($sessionpools.poolone.$new())

Or if the session instance is already set up in an object variable:


Do SessObj.$logon(hostname,username,password)
Do iResultsList.$definefromsqlclass('T_authors')

Then the $sessionobject may be assigned using:


Do iResultsList.$sessionobject.$assign(SessObj)

In this final case the object instance in SessObj is duplicated so that the $sessionobject is a
separate instance. However, both instances continue to refer to the same session. This is a
general rule for session instances, when an object instance is duplicated both instances refer
to the same underlying session. For example:
Calculate SessObj as $sessionpools.poolone.$new()
Calculate SessObj2 as SessObj

At this point both variables contain separate instances that refer to the same session and if
we now
Calculate SessObj as $clib.$classes.odbcobj.$new()

SessObj2 continues to refer to the original session whereas SessObj is now a separate object
Calculate SessObj2 as 0

Now no variables refer to the original session that is automatically returned to the pool.
A list defined from an SQL class also has the $statementobject property. This is a read-only
property which is the statement object that is being used by $sessionobject. The
$statementobject property is intended to be used in methods that are being overridden by a
table class ($select for example). Unlike $sessionobject it is not safe to assume
$statementobject will remain the same throughout the life of the list.

Table Class Methods and Sessions


The $sessionobject and $statementobject properties can be used to obtain a session and
statement when required so that a table instance may execute SQL. For example
A session pool poolone has been created using
Calculate lHostName as 'SqlServer'
Calculate lUserName as ''
Calculate lPassword as ''
Do $extobjects.ODBCDAM.$objects.ODBCSESS.$makepool('poolone',5,
lHostName,lUserName,lPassword) Returns #F

A list variable is then defined in the $construct method of a window class using
Do iResultsList.$definefromsqlclass('T_authors')

255

Chapter 8SQL Classes and Notation


In the table class T_authors $construct method a session instance is obtained from session
pool poolone and assigned to the $sessionobject property of the list variable using
Calculate lRef as $sessionpools.poolone.$new()
Do $cinst.$sessionobject.$assign(lRef) Returns #F

Where lRef is an item reference variable. In this situation $cinst is a reference to the list
variable iResultsList. Note that the statement object iResultsList.$statementobject is
created automatically and there is no need to use the $newstatement method to create it.
The table class enables the developer to override the default SQL methods, for example a
$select method to select all columns in the list variable
Begin statement
Sta: SELECT [$cinst.$sessionobject.$selectnames($cinst)] FROM
[$cinst.$servertablenames]
If len(pExtraQueryText)
Sta: [pExtraQueryText]
End If
End statement
Do $cinst.$statementobject.$prepare() Returns #F
If flag true
Do $cinst.$statementobject.$execute() Returns #F
End If
Quit method #F

Where pExtraQueryText is a character parameter containing SQL clauses to be appended


to the query.
The results of the select may be retrieved using a $fetch method in the table class containing
Do $cinst.$statementobject.$fetch($cinst,pNumberOfRows,kTrue)
Returns lFetchStatus
Quit method lFetchStatus

Where pNumberOfRows is an integer parameter containing the number of rows to be


fetched.
These methods may then be called from the window $construct method in order to build a
list using
Do iResultsList.$select() Returns #F
Do iResultsList.$fetch(9999) Returns lFetchStatus

256

SQL Classes and Sessions

Chapter 9ServerSpecific Programming


This chapter contains server-specific information for each of the proprietary databases and
middleware configurations that Omnis Studio supports, including information for:
Oracle
Sybase
DB2
MySQL
PostgreSQL
SQLite
ODBC
JDBC
Amazon SimpleDB
Almost every DBMS has its own specific, extra features that are not part of the SQL
standard. Some of these features are supported by sending a particular database command to
the server using the standard $prepare(), $execute(), and $execdirect() methods. Others are
implemented as special session and statement object properties and methods.

Server and Clientware Compatibility


Some aspects of functionality and compatibility are subject to frequent change with new
versions of server software or clientware. Check the Omnis web site for details of software
versions supported and middleware configurations at: www.omnis.net/dams. There you
can view the latest information about the Clientware supported by the different server
databases supported in the current version Omnis Studio.

Note to existing Omnis Users


The Data Access Modules (DAMs) previously referred to as non-visual or V3 DAMs
are now known as Object DAMs. Where reference is made to a DAM it is assumed to be
the new Object DAM type unless stated otherwise. By default, the Omnis Session Manager
displays only those session templates that use the new Object DAMs. If you want to use
older style (V2) DAMs, you can enable them from the SQL Browser on the Options tab.
257

Chapter 9Server-Specific Programming

Oracle
This section contains additional information you need to access an Oracle database,
including server-specific programming, PL/SQL, data type mapping to and from Oracle, as
well as troubleshooting. For general information about logging on and managing your
database using the Omnis SQL Browser, refer to the earlier parts of this manual.

Properties and Methods


In addition to the base properties and methods described in the SQL Programming
chapter, the Oracle DAM provides the following additional features.

Session Methods
Method

Description

$proxyas()

SessionObj.$proxyas(cUsername [,cPassword, lRoles]). Allows the


supplied user to connect to Oracle through the current connection, which
must already be logged-on. The session then acquires the roles and
privileges associated with that user. An additional list of roles to be used
with the proxy session can also be supplied if required. The list should
consist of a single column of type Character. The password should be
supplied if the proxy requires authentication by password.
$proxyas() can be called repeatedly with different usernames if required, in
which case the current proxy is implicitly terminated before the new proxy
is established.

$endproxy()

SessionObj.$endproxy(). Explicitly tests for and terminates a proxy session


if one exists, returning the session roles and privileges back to those of the
primary connection.

Session Properties

258

Property

Description

$nullasempty

Default value kFalse. If kTrue Null values are converted to empty


values when fetched from the database.

$emptyasnull

When kTrue, empty Omnis strings are inserted as NULL. When


kFalse, they are inserted as chr(0). $emptyasnull defaults to
kTrue.

$trailingspaces

Default value kFalse. If kFalse is specified any trailing spaces on


character data being inserted are stripped. If kTrue is specified,
trailing spaces are kept.

$maxvarchar2

Default is 2000. Specifies the length above which Omnis character


columns will be mapped to the LONG/CLOB data type in Oracle

Oracle
Property

Description
7 & 8. The max value is 4000 for DAMORA8 and 2000 for
DAMORA7. Setting $maxvarchar2 to zero forces all character data
to be mapped to the LONG/CLOB data type.

$nationaltonclob

Oracle 8 or above: is used to alter the default mapping of Omnis


Character and National types. By default, Omnis Character and National
fields with a subtype greater than $maxvarchar2 are mapped to the
NCLOB data type. By setting $nationaltonclob to kTrue only National
fields with a subtype >$maxvarchar2 are mapped as NCLOBs. Character
fields with subtype >maxvarchar2 are mapped as non-Unicode CLOBs.
Character fields mapped in this way are subject to data loss/truncation
where such fields contain Unicode characters.

$nationaltonvarchar

Only available in the Unicode DAM, $nationaltonvarchar is used to alter


the default mapping of Omnis Character and National types. By default,
Omnis Character and National fields with a subtype <= $maxvarchar2 are
mapped to the NVARCHAR2 data type. By setting $nationaltonvarchar
to kTrue only National fields with a subtype <= $maxvarchar2 are
mapped as NVARCHAR2. Character fields with subtype <=
$maxvarchar2 are mapped as non-Unicode VARCHAR2 columns.
Character fields mapped in this way are subject to data loss/truncation
where such fields contain Unicode characters.
Please note VARCHAR2 and NVARCHAR2 columns are limited to
4000 bytes. Hence NVARCHAR2 columns are limited to 2000 UTF-16
characters.

$internalcharmapping

If set to kFalse, conversion of non-Unicode character data to and


from the Omnis character set is disabled, even when
$charmap=kSessionCharMapOmnis or kSessionCharMapTable,
thus allowing custom character maps to be used with native
characters if required. Default setting is kTrue.

$nativewarncode

A warning code issued by the clientware in response to the last


session method to be executed.

$nativewarntext

A warning message issued by the clientware in response to the last


session method to be executed.

$booltonum

If set to kTrue, Omnis Boolean fields will be mapped to the


Oracle NUMBER(1,0) data type. Bound kTrue and kFalse values
will be written as 1 and 0, respectively. $createnames() will return
NUMBER(1,0) as opposed to VARCHAR2(3). When set to
kFalse (default), the old behavior is retained.

$authmode

Oracle 8 or above: Specifies the authentication mode to be used


with the connection. By default, kAuthDefault is used. If you have
sufficient privileges however, kAuthSysOper or kAuthSysDba can
be supplied. $authmode must be set before executing $logon().

259

Chapter 9Server-Specific Programming

260

Property

Description

$credentials

Specifies the type of credentials to be used for establishing the


connection. Valid modes are:
-Authentication via username and password (kCredRDBMS)
-Authentication using the Windows user account (kCredExt)
To establish a proxy connection, please refer to the $proxyas()
method.

$longchartoclob

If set to kTrue, Omnis large character fields > $maxvarchar2 in


length will be mapped to the CLOB data type. This affects inserts
and updates as well as the text returned by $createnames(). When
set to kFalse, the DAM maps long character fields to the Oracle
LONG data type (Oracle7 behaviour). This property is read-only
for DAMORA7 and defaults to kTrue for DAMORA8.

$binarytoblob

If set to kTrue, Omnis binary fields will be mapped to the BLOB


data type. This affects inserts and updates as well as the text
returned by $createnames().When set to kFalse, the DAM maps
binary fields to the Oracle LONG RAW data type (Oracle7
behaviour). This property is read-only for DAMORA7 and
defaults to kTrue for DAMORA8.

$newpassword

If set, the DAM will attempt to change the password during


$logon(). Intended to allow expired passwords to be changed but
can also be used in the general case.
If successful, the logon will proceed as normal, the $password
property will be updated and $newpassword will be cleared.
When changing the password, the existing username and password
should be passed via the $logon() method as normal.

$truetext & $falsetext

Studio 5.0 and later. Contain the text that will be inserted for
Boolean bind variables. Where these values where previously
taken from the Omnis localization datafile, these properties now
permit localization-independent values to be inserted, e.g. YES
& NO. For backwards compatibility, default values are taken
from Omnisloc.df1. Affects the text returned by $createnames()
and the size of buffers used to insert data.

$querytimeout

Studio 4.3.2/5.0.1 and later. This is the timeout in seconds for any
statement executed via $execute() or $execdirect(). Designed to
detect Unix network hangs, this property has no effect for Win32
and OS X. When a timeout occurs, the connection is marked bad
and a re-connect is necessary. Default value is 10 seconds.

Oracle

Statement Methods
Methods

Description

$plsql()

StatementObj.$plsql(cPLSQLtext[,iColNo...]). This function should


be used instead of $prepare() when you want to call server
procedures that contain bound OUT or IN/OUT parameters.

$prepareforupdate()

StatementObj.$prepareforupdate(vTableDef[,cTablename,cWhere])
creates and prepares a 'select for update' statement for specific use
with positioned updates and deletes.

$posdelete()

StatementObj.$posdelete(oStatement) deletes a row positioned by


the specified statement object.

$posupdate()

StatementObj.$posupdate(oStatement,wRow) updates a row


positioned by the specified statement object.

Statement Properties
Property

Description

$nativewarncode

A warning code issued by the clientware in response to the last


statement method to be executed.

$nativewarntext

A warning message issued by the clientware in response to the last


statement method to be executed.

$plsqlarraysize

When retrieving data into an Omnis list via PlSql, the number of rows
that will be fetched is not known until the plsql executes. Historically,
the DAM reserved a pre-determined buffer size of 32512 bytes per list
column to be fetched. If the actual number of rows fetched * column
size (in bytes) exceeds this limit for a given column, ORA-06513 is
returned.
The column buffer size is now set according to $plsqlarraysize (default
value 32512), thus the buffer size can be raised (or lowered) as
required in order to accommodate the entire result set.

Connecting to your Database


To connect to your database, you need to create a session object with a subtype
ORACLE8SESS (or the legacy subtype: ORACLE7SESS). In order to log on to the
database using the SessObj.$logon() method, the hostname must contain a valid Oracle host
alias previously generated by the Oracle client tools.

261

Chapter 9Server-Specific Programming

Mixing Unicode and Non-Unicode Data Types


This section summarises recent changes made to the Unicode Oracle Object DAM designed
to enable insertion and retrieval of mixed ANSI and Unicode character types.
In the case of Oracle 8i and later, these data types are:
CHAR

Fixed single-byte character data, limited to 2000 bytes.

NCHAR

Fixed multi-byte character data, limited to 2000 bytes.


(1000 UCS-2 encoded characters)

VARCHAR2

Varying length, single-byte character data, limited to 4000 bytes.

NVARCHAR2

Varying length, multi-byte character data, limited to 4000 bytes.


(2000 UCS-2 encoded characters)

CLOB

Character Large Object- single-byte character data.

NCLOB

National Character Large Object- multi-byte character data.

LONG

Varying length, single-byte character data, limited to 2GB.


Supported for backward compatibility only.

By default, the Unicode Oracle DAM maps all Omnis character data to the NVARCHAR2
and NCLOB data types, dependent on the field length of the Omnis bind variable. However,
the Oracle DAM provides session properties which affect the Omnis to Oracle data type
mappings:
$nationaltonvarchar
If set to kTrue, Character and National data types are treated differently when being
inserted to VARCHAR2 / NVARCHAR2 columns.
$nationaltonclob
If set to kTrue, large Character and National data types are treated differently when
being inserted to CLOB / NCLOB columns.
$maxvarchar2
Sets the byte limit above which Omnis character fields will be mapped to
CLOB/NCLOB data types as opposed to VARCHAR2 / NVARCHAR2 columns. The
maximum value is 4000 bytes.
$longchartoclob
If set to kTrue (the default), Omnis large character fields > $maxvarchar2 in byte length
will be mapped to the CLOB/NCLOB data type. If set to kFalse, the LONG data type is
used.

Reading Unicode and Non-Unicode Data


The Oracle DAM automatically detects the data type of retrieved character columns and
converts the data accordingly. There is no need to modify any properties in order to retrieve
mixed ANSI and/or Unicode Data.
262

Oracle

Insertion/Update of CHAR and VARCHAR2 data


To write short character data to ANSI columns it is necessary to set $nationaltonvarchar to
kTrue. In this mode, Omnis Character fields will be mapped to VARCHAR2 and National
fields will be mapped to NVARCHAR2.
When set to kFalse (the default), both Character and National types will be mapped to
NVARCHAR2.

Insertion/Update of CLOB data


Where the Omnis field length exceeds $maxvarchar2, the DAM will map to either CLOB,
NCLOB or LONG dependent on the value of the $nationaltonclob and $longchartoclob
properties. To write long character data to ANSI CLOB columns, it is necessary to set
$nationaltonclob to kTrue. In this mode, Omnis Character fields will be mapped to CLOB
and National fields will be mapped to NCLOB. When set to kFalse (the default), both
Character and National types with byte sizes exceeding $maxvarchar2 will be mapped to
NCLOB.
Note that where Omnis fields are mapped to NCLOB columns, $maxvarchar2 is interpreted
as the length in bytes. Thus when set to 4000, this mapping will be applied for Character
and/or National fields with a field length > 2000 characters

Insertion/Update of LONG data


When $longchartoclob is set to kFalse, Omnis Character and National fields which would
otherwise map to CLOB or NCLOB will be mapped to the LONG data type. Since Oracle
tables may contain only one column of type LONG, this may lead to problems if not used
judiciously.

PL/SQL
Oracle does not support the remote procedure call methods such as $rpc() which are
described in the SQL Programming chapter. Server procedures can be executed via
PL/SQL. The Oracle DAM fully supports Oracle PL/SQL; a procedural language that the
server executes.
You create a PL/SQL script and send it to Oracle in a similar way as any SQL statement and
the server executes it. The statement object method $plsql() should be used instead of
$prepare() when you want to call server procedures that contain bound OUT or IN/OUT
parameters. Any PL/SQL bind variables being passed to Oracle should be passed as Omnis
bind variables i.e. @[Xvar]. When $plsql() is called with bind variables, the DAM will
check to see whether any return values are present after execution and will return them back
into the Omnis variable. This does not happen after a $prepare(). If you are creating stored
procedures or executing a server procedure for which you do not expect a return value,
$prepare() will be sufficient.
263

Chapter 9Server-Specific Programming


; lEmpId is local Integer 32-bit with initial value of 0
Do StatObj.$plsql("begin select empno into @[lEmpId] from scott.emp
where ename = 'JONES'; end;")
Do StatObj.$execute()
If lEmpId <>7566
; Incorrect value returned from procedure
End If

After the PL/SQL executes, the Omnis variable lEmpId has the value associated with the
column id from the row with the name Jones.
The Oracle DAM supports select tables returned through PL/SQL procedures. However
Oracle can only return single column tables (arrays). The statement object method, $plsql(),
has optional parameters that follow the cPLSQLtext parameter. These are necessary when
calling server procedures that return single column tables. To bind a column of an Omnis
list to the select table being returned requires a list variable to be bound in the SQL
statement and the list column number to be passed as an additional parameter. If more than
one select table is being returned, multiple lists will need to be bound and a column number
parameter passed for each list, in the same order as the lists are bound. The bound lists do
not have to be different lists, the same list can be bound more than once in the PL/SQL
statement, but you must take care to specify a different column number for each occurrence
of the bound list. If no column number parameter is passed for a bound list, the first column
of the list is used by default.
Consider the following example table and PL/SQL package:
Table: accounts
id
NUMBER(3,0)
1
2
3
4
5
6
7
8
9

264

name
NVARCHAR2(256)
Bill
Sally
Bob
John
Graham
Helen
Betty
Walter
Sarah

balance
NUMBER(16,2)
2000
120
1000
1700
3000
2000
9000
25000
9100

limit
NUMBER(16,2)
2200
100
190
1500
21087
1860
1490
17200
10000

Oracle
create or replace package test as
type account_name is table of accounts.name%TYPE index by
binary_integer;
type account_balance is table of accounts.balance%TYPE index by
binary_integer;
end test;
create or replace procedure credit(accnum IN number, amount IN
number,pname out test.account_name, pbalance out
test.account_balance)
is
cursor c1 is select name,balance from accounts where balance >
limit;
row_count BINARY_INTEGER;
begin
row_count := 1;
update accounts set balance = balance + amount where id = accnum;
open c1;
LOOP
FETCH c1 INTO pname(row_count),pbalance(row_count);
row_count := row_count + 1;
exit when c1%NOTFOUND;
end LOOP;
close c1;
end;
; Local variables:
; lName=Character 256, lBalance=Number2dp, lCreaditList=List
Do SessObj.$blobsize.$assign(32767)
; Prevents ORA-06505
Do lCreditlist.$define(lName,lBalance)
Do StatObj.$plsql('begin credit(2,490,@[lCreditlist],
@[lCreditlist]); end;',1,2) Returns #F
Do StatObj.$execute() Returns #F
If Creditlist.$linecount<>6
; Incorrect data returned from stored procedure
End If

In the above example, the same list has been bound twice, the first bind variable binds the
first column of the list and the second bind variable binds the second column as defined by
the second and third parameters of the $plsql() method.

265

Chapter 9Server-Specific Programming


After the PL/SQL procedure executes, lCreditList should contain 6 rows as follows:
name

balance

Sally

610.00

Bob

1000.00

John

1700.00

Helen

2000.00

Betty

9000.00

Walter

25000.00

The balance of account id 2 (Sally) has been increased by 490. The procedure returns
details of those accounts where the balance column is greater than the limit column.

Positioned Updates and Deletes


You can use positioned updates and deletes to update and delete specific rows from the
select table you are fetching. To enable positioned updates and deletes the statement object
method, $prepareforupdate(), should be used. This method creates and prepares a 'select for
update' statement for specific use with positioned updates and deletes. A 'select for update'
SQL statement can be prepared using the $prepare() method. However, it will not store the
current ROWID in the statement object.
You can use $prepareforupdate() in conjunction with $posupdate() and $posdelete() to
update or delete a row, which is determined by the current row in the specified statement.
The 'select for update' statement is built based on the parameters passed. The columns will
be derived from the list or row passed as the first parameter. If the cTablename parameter is
omitted, the name of the list/row is assumed to be the name of the table. A SQL WHERE
clause is appended to the select statement if it has been specified. After this statement has
been executed the last row fetched will be seen to be the current row. If the statement does
not perform a fetch, there will not be a current row.
Note: For all position update and delete functionality the transaction mode must be
kSessionTranManual.

266

Oracle
;lEmpSt,lEmpUpSt,lEmpDelSt are Statement Object instances derived
from the same session
;lTableName is a Character(32) variable
;iTableList and lTempList are list variables defined from schema
class scPos1
;lDataRow is a row defined from schema class scPos1
; Fetch the row
Calculate lTableName as $classes.scPos1.$servertablename()
Do lEmpSt.$prepareforupdate(iTableList,lTableName)
Do lEmpSt.$execute()
Do lEmpSt.$fetch(lDataRow,1)
; Update this row
Calculate lDataRow.vala as 5 ;; change the value of one of the
columns
Do lEmpUpSt.$posupdate(lEmpSt,lDataRow)
Do lEmpUpSt.$execute()
; Fetch the next row
Do lEmpSt.$fetch(lTempList,2)
; delete this row
Do lEmpDelSt.$posdelete(lEmpSt)
Do lEmpDelSt.$execute()

Oracle 8 Data types


The Oracle8 DAM (DAMORA8) supercedes the older Oracle7 DAM (DAMORA7, which
is no longer in development). DAMORA8 has been specifically written to connect to
Oracle8 (and later) databases but can be used against an Oracle7 server using the
recommended clientware. In this case, the DAM will encounter restrictions as described
below, mainly concerned with data type mapping of large objects.

Large Objects (LOBS))


CLOBs, NCLOBs and BLOBs are data types introduced for Oracle 8 that deal with large
objects. Internal LOBs (BLOBs, CLOBs, NCLOBs) are stored in the database tablespaces
in a way that optimizes space and provides efficient access. These LOBs have the full
transactional support of the database server. The maximum length of a LOB/FILE is 4
gigabytes. Internal LOBs have copy semantics. Thus, if a LOB in one row is copied to a
LOB in another row, the actual LOB value is copied, and a new LOB locator is created for
the copied LOB.
The Oracle8 DAM uses locators to point to the data of a LOB or FILE. These locators are
invisible as the DAM performs operations on the locator to insert, update, delete and fetch
the values. This means that you are only ever dealing with the values of the LOBs and not
the locators.

267

Chapter 9Server-Specific Programming


You can work with the locators rather than just the values using PL/SQL in conjunction
with the dbms_lob package. Further information can be found in the Oracle8i Supplied
Packages Reference.
External LOBs (FILEs) are large data objects stored in the server's operating system files
outside the database tablespace. FILE functionality is read-only. Oracle currently supports
only binary files (BFILEs). The Oracle8 DAM uses locators to point to the data of a FILE.
The FILE locator will be invisible, as the DAM will return the value of the external file and
not the locator when performing transactions with the BFILE data type. Even though the
BFILE data type is read-only you can insert a directory alias and filename into the column.
These values are assigned to a single Omnis binary variable and separated by the '&'
symbol. The DAM will assign these values to the locator so that when a fetch is performed
on the locator the binary representation of the external file corresponding to the alias and
filename will be returned. An example is shown below.
; A Directory alias needs to be created on the server that points
; to an OS folder
myStat.$execdirect("create or replace directory sound as
'c:\bfiles'")
; BFILE1 and BFILE2 are Omnis variables of type Binary.
; The variable is calculated as
; '<DirectoryAlias>&<Filename>'.
Calculate BFILE1 as 'sound&wav2.wav'
Calculate BFILE2 as 'sound&wav3.wav'
myStat.$execdirect('insert into bfiletest
values(1,@[BFILE1],@[BFILE2])')
; You can now select the data back and this time you can receive the
binary representation of the file.
myStat.$execdirect('select * from bfiletest')
myStat.$fetch(myRow)
; The values contained in col2 and col3 of myRow can now be
; written to the local drive using the Omnis Fileops commands.
Calculate File as 'c:\windows\desktop\wavtest.wav'
Do Fileops.$createfile(File) Returns lErr
Do Fileops.$openfile(File) Returns lErr
Do Fileops.$writefile(myRow.2) Returns lErr
Do Fileops.$closefile() Returns lErr

268

Oracle

Ref Cursor Data Types


The REF CURSOR is an Oracle 8 data type that is used to point to a set of results from a
multi-row query. When executing a multi-row query, Oracle opens an unnamed work area
that stores processing information. To access the information, you can use a variable of type
REF CURSOR, which points to the work area. To create cursor variables, you define a REF
CURSOR type and then declare cursor variables of that type.
A REF CURSOR type can be defined in an Oracle Package object. For example:
create or replace package OmnisPackage
as
type cursorType is ref cursor;
end;

This data type can be used in other Oracle objects, such as procedures and functions in
order to process result sets. An example of a Stored function follows:
create or replace function OmnisFunction return
OmnisPackage.cursorType
as
l_cursor OmnisPackage.cursorType;
begin
open l_cursor for select * from scott.dept;
return l_cursor;
end;

An example of a stored procedure that uses the defined REF CURSOR type follows:
create or replace procedure OmnisProcedure
( p_cursor in out OmnisPackage.cursorType )
as
begin
open p_cursor for select ename, empno from scott.emp order by ename;
end;

Cursor variables are like pointers, which hold the memory location (address) of some item
instead of the item itself. So, declaring a cursor variable creates a pointer, not an item.
REF CURSOR data types can be returned in three different ways; via a PL/SQL block, an
Oracle Stored Function or an Oracle Stored Procedure. The REF CURSOR type is a pointer
to a result set. The SQL statement that returns the REF CURSOR must be prepared using
the $plsql() method. The Oracle 8 DAM maps the REF CURSOR type to an Omnis Oracle8
Statement Object*. The statement object will be created by the DAM and will belong to the
same session object as the Statement object that prepared the initial SQL. It will have a
$state of kStatementStateExecuted and, assuming that there is data in the result set, will
have $resultspending set to kTrue. Therefore, the statement object will be in a Ready-For
Fetch state. Below are examples of the three ways to return and use a REF CURSOR in
Omnis. The connection code and the creation of initial Statement Object (myStatement)
have been removed for clarity.
269

Chapter 9Server-Specific Programming


*As of Studio 5.2, the Object variable used to return the REF CURSOR result set may
instead be passed as an Object reference if preferred.

PL/SQL Block
The PL/SQL method does not require any SQL objects created on the server. All the
PL/SQL code can be encapsulated in an Omnis Statement block.
; declare vars: cursor1 (Object), myList1 (List)
Begin statement
Sta: begin
Sta: OPEN @[cursor1] FOR SELECT * FROM scott.emp;
Sta: end;
End statement
If myStatement.$plsql()
If myStatement.$execute()
Do cursor1.$fetch(myList1,kFetchAll)
; myList1 will contain the rows of the result set.
Else
OK message Error {[ myStatement.$nativeerrortext]}
End If
Else
OK message Error {[ myStatement.$nativeerrortext]}

End If

Stored Functions
Returning a REF CURSOR from a Stored Function requires an Oracle Stored Function on
the database. The Function must have a return type that has been defined as a REF
CURSOR. For this example we will assume that the example Oracle Stored Function
described above has been created on the server.
; declare vars: cursor2 (Object), myList2 (List)
If myStatement.$plsql('begin @[cursor2] := OmnisFunction; end;')
If myStatement.$execute()
Do cursor2.$fetch(myList2,kFetchAll)
; myList2 will contain the rows of the result set.
Else
OK message Error {[ myStatement.$nativeerrortext]}
End If
Else
OK message Error {[ myStatement.$nativeerrortext]}
End If

270

Oracle

Stored Procedures
Returning a REF CURSOR from an OUT or IN OUT parameter of a Stored Procedure
requires an Oracle Stored Procedure on the database. The Procedure must have an OUT or
IN OUT parameter type that has been defined as a REF CURSOR. For this example we will
assume that the example Oracle Stored Procedure described above has been created on the
server.
; declare vars: cursor3 (Object), MyList3 (List)
If myStatement.$plsql('begin getemps(@[cursor3]); end;')
If myStatement.$execute()
Do cursor3.$fetch(myList3,kFetchAll)
; myList3 will contain the rows of the result set.
Else
OK message Error {[ myStatement.$nativeerrortext]}
End If
Else
OK message Error {[ myStatement.$nativeerrortext]}
End If

Oracle 9i Data types


The Oracle 8 Object DAM includes support for data types added for Oracle 9i, namely the
XML and URI data types. The XML data type lets you store native XML documents
directly in an Oracle database and eliminates the need to parse the documents coming into
and out of the database. Server specific properties and methods have been added to the
DAM to support these enhanced database operations.
Oracle 9i also introduced several new Universal Resource Identifier (URI) types. These are
used to identify resources such as Web content anywhere on the Web and can be used to
point to data either internally or externally from the database itself. In addition to support
for URIs, the Oracle DAM includes support for querying and other abstract functions
provided for the URI types.
These changes were introduced with Omnis Studio version 3.2. The old-style, single
threaded DAM (DORACLE8) can connect to Oracle 9i databases, but does not support the
XML and URI data types.

XMLType
The XMLType is a system defined data type with predefined member functions to access
XML data. You can perform the following tasks with XMLType:
Create columns of XMLType and use XMLType member functions on instances of the
type.
Create PL/SQL functions and procedures, with XMLType as argument and return
parameters.
271

Chapter 9Server-Specific Programming


Store, index, and manipulate XML data in XMLType columns.

URIType
The URIType is an abstract object type that can store instances of HttpUriType or
DBUriType. Universal Resource Indicator references can point to XML, HTML and
custom internet content which can be located either locally within the database, externally to
the database but local to the server or remotely across an internet or network connection.

DBUriType
The DBUriType can obtain data pointed to by a DataBaseUri-reference. A DBUri-Ref is a
database relative URI that is a special case of the Uri-ref mechanism, where ref is
guaranteed to work inside the context of a database and session. This ref is not a global ref
like the HTTP URL, instead it is local ref (URL) within the database.

HttpUriType
The HttpUriType implements the HTTP protocol for accessing remote pages.

UriFactoryType
It is not possible to generate table columns using the UriFactoryType. Rather, this is a
PL/SQL package containing factory methods that can be used to generate the appropriate
instance of the Uri types without having to hard code the implementation in the program.
Custom URI types can be defined and registered using this package.
For further information on the application of these data types, refer to the Oracle9i
Application Developer's Guide XML.

Retrieving XML and URI data


In Oracle9i version 9.1, it is not possible to directly SELECT data from columns defined
using these types. Instead, the appropriate accessor functions should be used.
XMLType provides the extract(), getClobVal(), getStringVal(), and getNumberVal()
functions for data query and retrieval. The extract() function has to be used in conjunction
with one of the data type conversion functions, since it returns an object of type XMLType.
The following example SQL statement can be used to extract an XML document from an
XMLType column:
SELECT a.xmlcol.extract(*).getStringVal() AS mycol FROM mytable a

If required, the XPath expression parameter to the extract() function can be supplied using a
character bind variable. For further information on the extract() function and the supported
Xpath syntax, refer to the Oracle9i Application Developer's Guide XML.
URITYPE and its derivatives provide the getClob(), getUrl() and getExternalUrl() functions
for data retrieval. When getClob() is executed, the URL stored in the database column is
read. The document pointed to by the URL is then accessed and returned as CLOB data
which can be read into Omnis:
272

Oracle
SELECT a.myuri.getclob() AS mycol FROM mytable a

The getUrl() and getExternalUrl() functions return the URL contained in the database
column. (getExternalUrl() differs from getUrl in that it escapes the URL so that it better
conforms to the URL specification):
SELECT a.myuri.geturl() AS myurl FROM uritest a

The getClob(), getUrl() and getExternalUrl() functions can be overridden when creating
custom URI types as defined using the UriFactoryType. For information on the
UriFactoryType, refer to the Oracle9i Application Developer's Guide XML.

Inserting XML and URI data


To insert XML data into an XMLType column, the data must be a valid XML document or
fragment. This is because XMLType validates the XML before storing it. A simple insert
statement would be of the form:
INSERT INTO xmltable VALUES(,sys.XMLType.createXML (<DOC>
</DOC>),)

If required, the XML text can be supplied using a character bind variable.
XML data can also be supplied as CLOB data by inlining a SELECT statement (or some
other expression which returns a CLOB):
INSERT INTO xmltable SELECT id, sys.XMLType.createXML(myclob) FROM
clobtable;

Inlining ensures that createXML() receives a CLOB field, which is not possible from Omnis
since CLOBs are converted into Omnis character strings when fetched.
To insert a URL into a URIType column or one of its derivatives, use the createUri()
function. For example:
INSERT INTO uritest VALUES
(,sys.httpUriType.createUri(http://www.omnis.net),)

If required, the URL can be supplied using an Omnis character bind variable.

Updating XML and URI data


In version 9.1, Oracle9i stores XMLType internally using the CLOB data type. Updates on
CLOBs have to be performed on the entire column and for this reason, when updating an
XMLType column, it is necessary to re-insert the XML data.
UPDATE xmltest
SET xmlcol = sys.XMLType.createXml(@[iXMLText])
WHERE IDcol = @[iRecordNum]

Similarly, with URITypes, updates are performed as follows:

273

Chapter 9Server-Specific Programming


UPDATE uritable
SET uricol = sys.httpUriType.createUri(@[iHTMLURL])
WHERE IDcol = @[iRecordNum]

Oracle Data Type Mapping


The following tables describe the data type mapping for Omnis and Oracle.
Mappings are for the Oracle8 object DAM and Oracle versions 8i 11g and later.

Omnis to Oracle
Omnis Data Type
CHARACTER
[1]
Character/National <= the value of
$maxvarchar2 (default is 2000)
[1]
Character/National > the value of
$maxvarchar2 (default is 2000)
DATE/TIME
Short date (all subtypes)
Short time
Date time (#FDT)
NUMBER
Short integer (0 to 255)
Integer 64 bit
Integer 32 bit
Short number 0dp
Short number 2dp
Number floating dp
Number 0..14dp
OTHER
Boolean
Sequence
Picture
Binary
List
Row
Object
Item reference
[1]

ORACLE8 Data Type


NVARCHAR2(n)
NCLOB

DATE
DATE
DATE
NUMBER(3, 0)
NUMBER(19,0)
NUMBER(11, 0)
NUMBER(10, 0)
NUMBER(10, 2)
FLOAT
NUMBER(16, 0..14)
[2]

VARCHAR2(3)
NUMBER(11, 0)
[3]
BLOB
[3]
BLOB
[3]
BLOB
[3]
BLOB
[3]
BLOB
[3]
BLOB

Dependant on the values of $nationaltonvarchar, $nationaltonclob and $maxvarchar2


Dependant on the value of $booltonum
[3]
Dependant on the value of $binarytoblob
[2]

274

Oracle

Oracle to Omnis
Server Data Type

Omnis Data Type

CHARACTER
CHAR / NCHAR

Character

VARCHAR2 / NVARCHAR2

Character

CLOB / NCLOB

Character

BLOB

Binary

BFILE

Binary

LONG

Character

RAW

Binary

LONG RAW

Picture

DATE/TIME
DATE

Date time (#FDT)

NUMBER
NUMBER(p,0)

p>10

Integer 64 bit

NUMBER(p,s)

p<=10 or s>0

Number floating dp

NUMBER ( NUMBER(0,0) )

Number floating dp

FLOAT

Number floating dp

Oracle Troubleshooting
The following points may help in resolving issues in programming Omnis applications that
use an Oracle database.
When performing transactions that use the new LOB data types the transaction mode must
be set to either kSessionTranAutomatic or kSessionTranManual. This is because LOB and
file locators can not be used across transactions. The DAM performs functionality on these
locators and when the transaction mode is either automatic or manual, the DAM can control
when to commit the command, which would be after all the LOB functionality has been
performed. When the transaction mode is server, Oracle commits (or rollbacks) after every
statement and any LOB functionality performed by the DAM would result in an error.
Oracle has a client character set and a server character set. If the two are not the same
character set, Oracle will convert between the two. If a character in the client character set
also exists in the server character set, Oracle will store that character on the server. If the
character doesnt exist in the server character set, Oracle will do one of two things. Firstly,
Oracle will see if there is a close-fit character. For example, if you are trying to insert the
character , but that particular character is not in the server character set, Oracle will store
that character as an a as it is a close-fit. If there is not a close-fit character, Oracle will
275

Chapter 9Server-Specific Programming


store that character as an unknown character on the server. This unknown character is
usually . If the client character set is the same as the server character set, no conversion
takes place and all ASCII values of characters are preserved. On retrieval of characters
Oracle will again convert but this time from the characters stored in the Oracle database to
the clients character set being used to retrieve the text.
As with inserting Oracle will convert a character in the server character set to the same
character in the client character set if it exists. If not, it will try a best fit solution before
returning its unknown character. To guarantee that Oracle doesnt convert the data in the
database, the client character set should be the same as the server character set. It is possible
to use Omnis character maps to change some of the characters which arent correct to ones
that are preferred (Non-Unicode session objects only). This is useful when Oracle returns a
best fit character and not the original character.
Further troubleshooting notes, how-tos and tips can be found on the Omnis website at:
www.omnis.net/technotes

276

Sybase

Sybase
This section contains the additional information you need to access a Sybase database,
including server-specific programming, data type mapping to and from Sybase, as well as
troubleshooting. For general information about logging on and managing your database
using the Omnis SQL Browser, refer to the earlier parts of this manual.

Properties and Methods


In addition to the base properties and methods documented in the SQL Programming
chapter, the Sybase DAM provides the following additional features.

Session Properties
Property

Description

$programname

The program name that is registered by Sybase at logon. The default is


$clib().$name.

$logontimeout

The timeout in seconds for a logon. The default is 60 seconds. Set this
to 0 for no timeout. Note that a timeout is ignored if $failtimeout is
kFalse.

$querytimeout

Timeout in seconds for a query. The default is 0 for no timeout. Note


that a timeout is ignored if $failtimeout is kFalse.

$failtimeout

Set to kTrue to raise an error if a timeout occurs. If kTrue and a


timeout occurs the connection is marked as dead and the session is
logged off.

$encryptpassword

Set to kTrue to use password encryption when logging on. The default
is kFalse.

$cterrorlayer

Layer at which the current session client error occurred. Read only.

$cterrororigin

Origin of current session client error. Read only.

$cterrorseverity

Severity of current session client error. Read only.

$cterrornumber

Error number of current session client error. Read only.

$moneydps

This property determines the number of decimal places used to store


and display data retrieved from MONEY columns. It is also used
when creating schemas- provided that this property is set before
dragging the table into the library. $moneydps defaults to 4 for
backward compatibility but can be set to 0, 1, 2, 3, 4, 5, 6, 8, 10, 12 or
14.

277

Chapter 9Server-Specific Programming


Property

Description

$locale

The locale name that will be used by the connection. This is initially
set to the default locale contained in the Sybase locales.dat file.
$locale may be set to a different value provided that the DAM is not
logged on.
Valid locale strings include locale names or language-character set
pairs contained in the locales.dat file for which the corresponding
language modules are installed. Assignment fails if the locale
information specified cannot be found or is not installed.

$nationaltounichar

Studio 5.1. When this property is set to kTrue, Omnis National


Character fields will be mapped to Sybase ASE UNIVARCHAR
columns using the UTF-16 encoding. Also affects the text returned by
$createnames(). When kFalse (the default), all Character fields are
mapped to VARCHAR columns (supporting the UTF-8 encoding).

Session Methods

278

Method

Description

$setremotepassword()

SessObj.$setremotepassword(cServerName, cPassword). Set a


password for a remote server connection. This will fail if the
session is logged on. If cServerName is NULL, the password is
used as a universal password for all servers with no specified
password.

$clearremotepasswords()

SessObj.$clearremotepasswords(). Clear all passwords for


remote server connections.

Sybase

Statement Properties
Property

Description

$cterrorlayer

Layer at which the current session client error occurred. Read


only.

$cterrororigin

Origin of current session client error. Read only.

$cterrorseverity

Severity of current session client error. Read only.

$cterrornumber

Error number of current session client error. Read only.

$rpcparamspending

If kTrue this denotes that an rpc parameter result set is pending.

$bindshort0dpassmallint

If kTrue, Short number 0dp parameters are bound to the server


as SMALLINTs. Otherwise the default mapping is usedNUMERIC(9,0).

$emptystringisblank

When set to kTrue, the DAM inserts empty character strings


into VARCHAR columns as single space characters. When set
to kFalse, a NULL or chr(0) is inserted. $emptystringisblank
defaults to kTrue. $emptystringisblank does not affect Omnis
character strings >255 characters which map to TEXT
columns. Empty TEXT values are always inserted as single
space characters.

Statement Methods
Method

Description

$cancelresultset()

StatementObj.$cancelresultset(). Cancel the current result set. This


will allow any further result sets to be processed. If the statement is
using a cursor, the cursor is closed and its results are discarded.

$writelob()

StatementObj.$writelob(vVariable, cTablename, cColumnname


[,cWHERE-clause, bUselog = kTrue]).
Updates a single image or text column with the value of vVariable.
The cTablename, cColumnname and optional WHERE clause identify
the table column to be updated. If bUselog is kTrue, changes may be
rolled back

Connecting to your Database


To connect to your database, you need to create a session object with a subtype of
SYBASESESS. In order to log on to the database using the SessObj.$logon() method, the
hostname must contain a valid Sybase host alias previously generated by the Sybase client
tools (see your Sybase documentation for more details).

279

Chapter 9Server-Specific Programming

Multiple Select Tables


The Sybase DAM lets you run more than one SQL SELECT statement at once and return
multiple select tables, one after the other. If a $fetch() call processes the last row of the
current result set, the call returns kFetchFinished. If the statement has further result sets
available, the statements $resultspending property will be kTrue. The application can then
process the next result set using $fetch().
One way to do multiple SELECTs is to code a procedure containing several SELECT
statements that is to execute on the server. The example below executes the following
procedure (assuming the number of lines in your list is adequate to contain all the rows
returned):
create proc multi_select as
SELECT firstName, lastName FROM Agents
SELECT id, name FROM Customers

To execute this from an Omnis method and to fetch the results:


Do
Do
Do
If

tStatement.$execdirect('exec multi_select') Returns #F


My_List1.$define()
tStatement.$fetch(My_List1,kFetchAll) Returns #1
#1=kFetchFinished & tStatement.$resultspending=kTrue
Do My_List1.$define()
Do tStatement.$fetch(My_List1,kFetchAll) Returns #1
End If

The Sybase DAM reports the select tables exactly as Open Client reports them. If a select
result set has no rows, $fetch() will return kFetchFinished the first time it is invoked for that
set.

Program Name
The Sybase sysprocesses table (in the master database) has a program_name column that
stores a separate name for each connection to the server. The session $programname
property lets you put a name into this column for the current session so that you can use it to
distinguish multiple sessions.
The default name is the name of the current library, i.e. $clib().$name If you wish to change
this you must set this property before logging on to the server, because the value gets set at
logon. If the value is set after logon it does not take affect until the session is logged on
again. The value persists across logons and logoffs, and $clear() does not reset it.
If the string assigned to the property is too long, the DAM truncates it without reporting an
error. The DAM can store a maximum of 255 characters but the program_name field in the
sysprocesses table currently only allows 16.

280

Sybase

Error Handling
If an error is raised on either a Sybase session or statement object, the $errorcode and
$errortext properties associated with the object will provide the generic error code and error
text. If there is an associated native Sybase server or client error this will be returned in the
$nativeerrorcode and $nativeerrortext properties associated with the object.
It is possible for an Omnis command to generate multiple Sybase server and client error
messages. If this is the case, the objects $nativeerrorpending property will be set to kTrue.
To retrieve the next set of error information the application can use the $nextnativeerror()
method. The DAM will return server errors and then client errors in the order in which they
were generated. Any informational messages returned from Sybase are ignored.
If a new Sybase DAM command is issued or a Sybase property is set, the current error
information for that object is cleared. The error set for the session is shared between the
session and all statements in that session. If a session or statement clears the current error
set, any other statement with multiple errors pending will only be able to retrieve the last
cached error since the error set will have been cleared.
You should be aware that the Sybase server and client errors reported may have codes and
messages that sometimes differ between the OS X and Windows Sybase clients.
The Sybase DAM defines several of its own internal error codes. These are returned in the
$nativeerrorcode and $nativeerrortext properties of the session and statement.
Error Code

Description

20000

The Omnis bind variable could not be mapped to an equivalent Sybase


type.

20005

The session must not be logged on.

20010

The login timeout value must be >= 0.

20011

The query timeout value must be >= 0.

20030

Sybase TEXT and IMAGE columns can not be bound as part of an


RPC call.

20050

The Omnis field can not be null or empty.

20051

The table name must be a character string which is not null or empty

20052

The column name must be a character string which is not null or empty

20053

The WHERE-clause must be a character string

20054

The column to be updated was not a TEXT or IMAGE column

20055

A memory allocation error occurred during the $writelob command

If a Sybase session or statement object generates an Open Client error, the error code is
decoded into the $cterrorlayer, $cterrorseverity, $cterrororigin and $cterrornumber. Sybase

281

Chapter 9Server-Specific Programming


Open Client errors use these 4 error components to provide more detail about the error
raised.
If a timeout error occurs and the sessions $failtimeout property is kTrue, a timeout error
will be raised, the connection will be marked as dead and the session will be logged off. If
the $failtimeout is set to kFalse (the default) the connection or query will be re-tried.

Large Objects (LOBs)


The Sybase Object DAM can send and retrieve text and image fields which are referred to
as LOBs or large objects. You can insert, update and fetch the fields using the standard
SQL object methods or you can use the $writelob() method to update a text or image field
on the DBMS, with the implicit functionality to retrieve a large text or image field.
Transferring BLOBs is very memory-intensive, since each layer of software has a copy of at
least part of the blob. Thus, sending a simple 40K picture can demand several times that
amount of RAM before it gets passed over to the DBMS. Therefore an application must
have sufficient memory resources to transfer large text and image data. The built in
chunking mechanism can be used to reduce the amount of memory Omnis requires to
transfer a LOB value. For example, the default settings for the sessions $lobthreshold and
$chunksize properties ensure that data greater than 32K is sent in chunks no greater than
32K. The chunksize and threshold can be altered to suit the resources available. If a system
has more memory, the threshold and chunksize can be increased to send fewer, larger
chunks.
There are no limitations, aside from memory concerns, on sending or retrieving multiple
LOBs in one SQL statement.
You should not forget to set the textsize parameter on the server. This parameter tells the
server to truncate all outgoing values to this setting (see your Sybase documentation for
more details). Therefore, if you set the textsize parameter to the default of 32,767 and select
a 500K image, you get a 32,767 byte value in Omnis.
Do tStatement.$execdirect('set textsize 123456')
; this sets the textsize parameter, for this session, to about 123K

This setting is for fetching values only. When fetching LOBs under MacOS Classic using
the standard commands, you should not set this parameter to its largest value. Increasing
this also causes Open Client to allocate more memory to deal with the larger LOBs.
Therefore, setting it too small will truncate your fetched data while setting it too large may
cause Open Client to kill your connection. If you are retrieving a variety of LOBs, you
should try to set it as closely as you can to the size of the largest LOB; you can set this for
each SQL statement sent. You can also use the Sybase datalength() function to find out how
long the value is that you want to retrieve, and use this to set the textsize parameter.
The Sybase DAM provides a faster and more memory efficient way to update a text or
image column through the use of the statement method $writelob(). To use the $writelob()
method you must already have the row in the database and the column value that is being
282

Sybase
updated must have non-NULL data in it.. You would usually create the row with a blank (' ')
in the column, for instance, use the $writelob() method to update the value with the LOB
data.
Do tStatement.$execdirect ("insert into mytable (x, mycol) values
(2, ' ')")
Do tStatement.$writelob(LOB_DATA,'mytable','mycol','where
x=2',kTrue)

This command places the value of the Omnis field LOB_DATA into the column mycol of
the table mytable in the row where x has the value of 2. Thus, the method places a single
LOB value into a location that you specify.
The method is defined as:
StatementObj.$writelob(vVariable, cTablename, cColumnname [,cWHEREclause, bUselog = kTrue])

The vVariable parameter is the Omnis variable containing the data to be sent to the server,
in the example this is LOB_DATA. This variable cannot be NULL or empty.
The cTablename and cColumnname parameters identify the table and column to update.
These can not be NULL or empty.
The cWHERE-clause parameter supplies an optional WHERE clause for a SQL SELECT
statement, including the word WHERE. If your WHERE clause is ambiguous Omnis
updates the first LOB value it finds, so the value updated may not be the one you intended.
Make sure your clause specifies a unique row.
The bUseLog parameter denotes whether to log this action in the transaction log. If you do
not log the action, you cannot roll it back. The default is kTrue to log the update. Setting
this parameter to kFalse requires that the select into/bulkcopy option be set to true with the
system procedure sp_dboption for the database on the DBMS. If you do not wish to log
updates, you must consult your documentation and system administrator as this may have
significant ramifications on being able to backup and recover your database.
The $writelob() method sets the flag false and sets error information in the same way as a
standard statement method.
Sybase recommend that data should be updated using the $writelob() method if the data size
exceeds 100K.

Remote Procedure Calls


The Sybase DAM supports the use of the session method $rpcdefine() to define a remote
procedure and the statement method $rpc() to call a procedure. The DAM does not support
the statement methods $rpcprocedures() and $rpcparameters().
An application must generate the parameter list passed to $rpcdefine() to describe the
parameters in the Sybase procedure. When a $rpc() call invokes the procedure the

283

Chapter 9Server-Specific Programming


parameters passed are mapped from their Omnis type definition to the equivalent Sybase
type in the same way as standard Omnis bind variables. A $rpc() call will fail if a parameter
definition includes an Omnis character or binary field larger than 255 since the parameter
will map to a text or image field which are not valid for use as parameters in Sybase stored
procedures.
If an rpc definition defines parameters of type kParameterInputOutput, these are treated as
output parameters since Sybase does not support updateable input parameters. The DAM
cannot update output parameters directly. If the procedure uses output parameters these
must still be specified in the call to $rpc() and are returned as a parameter result set which is
available when the statement property $rpcparamspending is kTrue. They must be
processed by the application in the same way as a normal result set. Any result sets
generated by the stored procedure must be processed before the parameter results become
available. The return status should not be included in the call to $rpc() as this will be set in
the statement $rpcreturnvalue property which is set after the stored procedure results are
processed.
The following creates a Sybase stored procedure which takes 2 input parameters and 1
output parameter. This procedure returns two result sets.
Do tStatement.$execdirect('create procedure Test_SYBRPC @parm1
varchar(30), @parm2 varchar(30), @parm3 varchar(60) OUTPUT AS
SELECT @parm3 = @parm1+@parm2 SELECT * from sysusers execute
sp_who RETURN 12345')

A list is used to define this procedure in the Sybase session.


Do
Do
Do
Do
Do
Do

#L1.$define(#1,#2,#3,#4) Returns #F
#L1.$add(kInteger,kLongint,0,kParameterReturnValue)
#L1.$add(kCharacter,kSimplechar,30,kParameterInput)
#L1.$add(kCharacter,kSimplechar,30,kParameterInput)
#L1.$add(kCharacter,kSimplechar,30,kParameterOutput)
tSession.$rpcdefine('Test_SYBRPC',#L1) Returns #F

The procedure can then be called.


Calculate Parm1 as 'Hello '
;; Character 30
Calculate Parm2 as ' There'
;; Character 30
Calculate Parm3 as
;; Character 60
Do tStatement.$rpc('Test_SYBRPC',Parm1,Parm2,Parm3) Returns #F

Since the stored procedure generates two result sets these must be processed first.
This will fetch the results from the sysusers and sp_who queries.

284

Sybase
If tStatement.$resultspending=kTrue
Do #L1.$define()
Do tStatement.$fetch(#L1,kFetchAll) Returns #1
End If
If tStatement.$resultspending=kTrue
Do #L1.$define()
Do tStatement.$fetch(#L1,kFetchAll) Returns #1
End If

The stored procedure return status is placed in the statements $rpcreturnvalue property and
the parameter result set is then available.
Calculate #1 as tStatement.$rpcreturnvalue ;; will set #1 to 12345
If tStatement.$rpcparamspending=kTrue
Do #L1.$define()
Do tStatement.$fetch(#L1) Returns #1
End If
Calculate Parm3 as #L1.1.1
;; will set Parm3 to 'Hello There'

An RPC or stored procedure can invoke procedures on another server. To do this, the server
that the first procedure is running on must log onto the other server and for this you can set
up a password to use when logging onto that server. The Sybase session object provides the
$setremotepassword() method to allow you to set up remote passwords. This associates the
specified password with the specified server for this connection to the DBMS. You can call
this multiple times to establish passwords for different servers.
If the server name is NULL, the password is a 'universal' password that you can use with
any server for which you haven't already established a password.
To clear all remote passwords use the $clearremotepasswords() session method.

Multiple Cursors
If a statement is issued without using a cursor, i.e. $usecursor is set to kFalse, any results
generated will block the connection and no other operation on any other statement can be
performed until the blocking result set is completely fetched or cancelled. To avoid
blocking the connection with pending results, use a statement which has the $usecursor set
to kTrue. Note that a statement using a Sybase cursor must have a unique statement name
and only allows SQL SELECT and EXECUTE procedure commands to be issued.

Meta-Data Queries
As of Studio 5.1.1, the $indexes() meta data method returns additional information via the
DamInfoRow column. The DamInfoRow will be defined with the following columns (as
returned by the sp_statistics stored procedure):
TableName

Character column containing the table name passed previously.


285

Chapter 9Server-Specific Programming


IndexQualifier

Character column indicating the index owner. For Sybase, this is usually
the same as TableName.

IndexType

Character column indicating the index type,


e.g. Clustered or Non-Clustered.

Collation

Character column indicating the collation type,


either Ascending or Descending.

Cardinality

Integer column containing the number of indexed or unique rows.

Pages

Integer column containing the number of pages used to store the index.

Logon Problems using the SYBASEDAM


In the event of connection problems, there are a number of Technotes available on the
Omnis website which discuss Sybase connection issues in greater detail.
Possible causes:
The $SYBASE/interfaces file is missing or the contents are invalid- follow the
installation tasks outlined above.
The logon hostname does not match the name contained in the $SYBASE/interfaces
file- check the contents of the interfaces file, paying attention to upper and lower case
characters.
The supplied username and/or password were incorrect- check at the server.
The xcomp:ini:sybasedam.ini file was not found or one or more of the
environment variables are set to incorrect values. Review this file.
The DAM does not load. The dynamic linker may be unable to locate the required
Sybase client libraries. Check environment variables (DYLD_LIBRARY_PATH for
OS X, LD_LIBRARY_PATH for Linux)

Sybase Troubleshooting
The following points may help in resolving issues in programming Omnis applications that
use a Sybase database.
Sybase is a case-sensitive RDBMS. Check the case of the table or column names if you
can see a table but cannot select anything out of it
Sybase defaults to NOT NULL columns; you must initialize columns to a specific value
while inserting data, or insertion will fail
Any number with no digits after the decimal point, that is > +/- 231 will generate an
error and not be inserted. This is because Sybase tries to parse numbers without
decimal points as integers

286

Sybase
Sybase does not support binding a NULL Boolean field in Omnis to a Sybase bit field
Sybase does some character mapping where required, but you may need to do character
conversion explicitly using the Omnis character mapping tables.
Sybase interprets empty strings as single spaces.
Fetching pictures from Sybase stored there by other applications, even in standard
formats, is likely to cause problems, since Omnis stores all pictures in a special format.
This occurs even in platform-specific graphics formats such as PICT or BMP.
The $tables() session method can only report information about tables in the current
database and does not return system tables.
The $columns() session method can only report information about tables owned by the
current user in the current database.
The $indexes() session method can only report information about indexes on tables in
the current database.
Sybase does not allow DDL statements to be issued within a user defined transaction,
i.e. do not use statements such as CREATE, DROP and ALTER when the sessions
transaction mode is kSessionTranManual. Do not use the $indexes() method using
kSessionTranManual since this method creates a table.
Sybase automatically strips spaces from character data returned to Omnis.
Data buffers could not be allocated error following a logon attempt:
This error normally occurs if the Sybase environment variables; SYBASE,
SYBASE_OCS and/or LANG/LC_ALL are not correct.
Check the sybinit.err file (in the Omnis folder) for more details about the error.
Further troubleshooting notes, how-tos and tips can be found on the Omnis website at:
www.omnis.net/technotes

287

Chapter 9Server-Specific Programming

Sybase Data Type Mapping


The following tables describe the data type mapping for Omnis and Sybase.

Omnis to Sybase
Omnis Data Type
CHARACTER
Character/National 0
Character/National 1 <= n <= 255
Character/National > 255
DATE/TIME
Short date (all subtypes)
Short time
Date time (#FDT)
NUMBER
Short integer (0 to 255)
Integer 32 bit
Integer 64 bit
Short number 0dp
Short number 2dp
Number floating dp
Number 0..14dp
OTHER
Boolean
Sequence
Binary/Picture/List/Row/Object/Item
reference where $blobsize <= 255
Binary/Picture/List/Row/Object/Item
reference where $blobsize > 255

288

Sybase Data Type


varchar(1)
varchar(n)
text
datetime
datetime
datetime
tinyint
int
bigint
numeric(9,0)
numeric(9,2)
double precision
numeric(15,0..14)
bit
int
varbinary($blobsize)
image

Sybase

Sybase to Omnis
Sybase Data Type
CHARACTER
char(n)
varchar(n)
nchar(n)
nvarchar(n)
text
DATE/TIME
datetime
smalldatetime
NUMBER
tinyint
smallint
int
bigint
numeric(p,n)
decimal(p,n)
real
float
double precision
money
smallmoney
OTHER
bit
binary(n)
varbinary(n)
image

Omnis Data Type


Character n
Character n
Character n
Character n
Character 10,000,000
Date time (#FDT)
Date time (#FDT)
Short integer (0 to 255)
Short number 0dp
Integer 32 bit
Integer 64 bit
Number (n)dp
Number (n)dp
Number floating dp
Number floating dp
Number floating dp
Number 4dp
Number 4dp
Boolean
Binary
Binary
Binary

289

Chapter 9Server-Specific Programming

DB2
This section contains the additional information you need to access a DB2 Universal Server
database, including server-specific programming, data type mapping to and from DB2, as
well as troubleshooting. For general information about logging on and managing your
database using the Omnis SQL Browser, refer to the earlier parts of this manual.

Properties and Methods


In addition to the base properties and methods documented in the SQL Programming
chapter, the DB2 DAM provides the following additional features.

Session Properties
Property

Description

$datetimeformat

This stores an Omnis date format string used to map a Date


time (#FDT) bind variable to the correct server
representation. This is necessary as DB2 supports different
regional timestamp formats. The date is stored on the
server in an internal binary representation.
The default format is 'y-M-D H:N:S'
This method is equivalent to the old-style
<DATETIME_FORMAT> keyword.

$drivername

The name of the session driver.

$driverodbcversion

The version number of the session driver.

Session Methods

290

Method

Description

$getdatasources()

SessionObj.$getdatasources(lListOrRow) populates the list


with the name and description of the data sources defined
on the client machine.
The list is redefined as having two columnsDataSourceName and Description. DataSourceName is
defined as Character 32. Description is defined as
Character 255.
This method is equivalent to the old-style
<GET_DATASOURCES> keyword.

DB2

Statement Properties
Property

Description

$erroronnodata

If set to kTrue (default), $execute() and $execdirect() will


fail if execution returns SQL_NO_DATA, i.e. if a row
addressed by the SQL statement could not be found. If set
to kFalse, SQL_NO_DATA errors are ignored to be
consistent with other databases. $erroronnodata does not
affect SELECT statements.

Connecting to your Database


To connect to your database, you need to create a session object with a subtype of
DB2SESS. In order to log on to the database using the SessObj.$logon() method, the
hostname must contain the catalog database name entered using the DB2 Command Line
Processor or using the Client Configuration Assistant if installed. The user name and
password should contain the values required by the database. For example:
Do SessObj.$logon(MyDatabase,UserID,Password,MySession)
Returns #F

In the event of connection failure, the DAM will timeout as dictated by any timeout policy
in use by the server. Logon failures are usually reported immediately.

Transactions
Generally, using manual transaction mode results in increased performance because the
session object does not force a commit after each statement.
If you do not have a results set pending, the DB2 session object will commit each statement
if the transaction mode is automatic. If the transaction mode is server, the server commits
the statement automatically.

Dates
The session property $defaultdate allows default values to be added to date values mapped
to the server where the Omnis date value does not contain complete information, e.g. when
a Short time is mapped to a server DATETIME. The date stored in this property is in a
generic format, i.e. it is compatible with any regional date format that the server may be
using.

291

Chapter 9Server-Specific Programming

Boolean Type
DB2 does not include a specific type for storing single bit data. The Omnis Boolean type is
therefore converted to a CHAR(3) value and stored as YES or NO in the server table.
The string representation can then be mapped back to an Omnis Boolean type when the data
is retrieved.

BLOB Type
The session property $blobsize can be used to specify the size argument for columns of type
BLOB generated when the $createnames and $coltext methods are used.
Values range from 1 to 10000000. The default value for $blobsize is 10000000 which is
also the maximum size of an Omnis binary variable.
This property is equivalent to the old-style <SETBLOBSIZE> keyword.

Meta-Data Queries
The meta-data statement methods $columns(), $indexes() and $tables() allow you to receive
information about the objects in your database. The $tables() method takes an optional
owner name as a parameter. The $indexes() and $columns() methods optionally take the
database and/or owner name with the table name parameter. See SQL Programming for
more information on these methods.
When a database, owner or table name is specified, the result set is constrained by those
schemas which meet the filter criterion, i.e. to return column information about the
addressbk table owned by robert in database acc_db the following can be issued.
Do tStatement.$columns('acc_db.robert.addressbk') Returns #F

DB2 Troubleshooting
Reserved Words
This section covers the DB2 specific reserved words.
The following schema names are reserved: SYSCAT, SYSFUN, SYSIBM & SYSSTAT.
In addition, it is strongly recommended that schema names never begin with the SYS prefix,
as SYS is by convention used to indicate an area reserved by the system.
There are no words that are specifically reserved words in DB2. Keywords can be used as
ordinary identifiers, except in a context where they could also be interpreted as SQL
keywords. In such cases, the word must be specified as a delimited identifier. For example,
COUNT cannot be used as a column name in a SELECT statement unless it is delimited.
IBM SQL and ISO/ANSI SQL92 include reserved words, these reserved words are not
enforced by DB2 Universal Database, however it is recommended that they not be used as
292

DB2
ordinary identifiers, since this reduces portability. Please see the final chapter in this manual
which lists the SQL reserved words.
Further troubleshooting notes, how-tos and tips can be found on the Omnis website at:
www.omnis.net/technotes

DB2 Data Type Mapping


The following table describes the data type mapping for Omnis to DB2 connections. This
mapping is predefined and is based on the best fit for each of the Omnis data types.

Omnis to DB2 UDB


Omnis data type
CHARACTER
Character/National(n) <= 4000
4000 < Character/National(n) <= 32,700
Character/National(n) > 32,700
DATE/TIME
Short date (all subtypes)
Short time
Date time (#FDT)
NUMBER
Short integer
Integer 32 bit
Integer 64 bit
Short number 0 dp
Short number 2 dp
Number 0..14 dp
OTHER
Boolean
Sequence
Picture
Binary
List
Row
Object
Item reference

Server data type


VARCHAR(n)
LONG VARCHAR(n)
CLOB(n)
DATE
TIME
DATETIME
SMALLINT
INTEGER
BIGINT
DOUBLE
DOUBLE
DOUBLE
CHAR (3)
INTEGER
BLOB($blobsize)
BLOB($blobsize)
BLOB($blobsize)
BLOB($blobsize)
BLOB($blobsize)
N/A

293

Chapter 9Server-Specific Programming

DB2 UDB to Omnis


Server Data Type

Omnis Data Type

NUMBER
SMALLINT

Integer 32 bit

INTEGER

Integer 32 bit

BIGINT

Integer 64 bit

DECIMAL(p,s)

Number (s)dp

NUMERIC(p,s)

Number (s)dp

FLOAT

Number floating dp

REAL

Number floating dp

DOUBLE

Number floating dp

CHARACTER
CHAR(n)

Character (n)

VARCHAR(n)

Character (n)

LONG VARCHAR(n)

Character (n)

CLOB(n)

Character (n)

DATE/TIME
DATE

Short date

TIME

Short time

TIMESTAMP

Date time (#FDT)

BINARY
BINARY

Binary

VARBINARY

Binary

LONGVARBINARY

Binary

BLOB

Binary

EXTENDERS

294

IMAGE

Binary

AUDIO

Binary

VIDEO

Binary

TEXT

Binary

MySQL

MySQL
This section contains the additional information you need to access a MySQL database,
including server-specific programming, data type mapping to and from MySQL, as well as
troubleshooting. For general information about logging on and managing your database
using the Omnis SQL Browser, refer to the earlier parts of this manual.

Properties and Methods


In addition to the base properties and methods documented in the SQL Programming
chapter, the MySQL DAM provides the following additional features.

Session Properties
Property

Description

$clientflags

SessObj.$clientflags sets the optional client flags logon parameter before


executing $logon(), (The value can consist of several values added together if
required). Their use is beyond the scope of this text and the default value of
zero should be suitable for most purposes. Client flags are discussed further in
the MySQL C API reference under mysql_real_connect().

$database

SessObj.$database sets the additional database logon parameter before


executing $logon(). Once logged on however, assigning a new value to this
property causes the current database to change. When the session is created, a
default value of mysql is assigned to this property.

$hostinfo

SessObj.$hostinfo describes the type of connection in use, including the


server host name. (Read-only)

$logontimeout

The number of seconds before a connection attempt times out.


SessObj.$connectoption() can also be used to set a logon timeout if required.

$port

SessObj.$port sets the additional port logon parameter before executing


$logon(). This will be the port number for a TCP/IP connection. The default
port number is 3306.

$protoversion

SessObj.$protoversion is the version of the protocol in use by the current


connection. (Read-only)

$socket

SessObj.$socket is the socket or named pipe that should be used for the
connection, applicable to non-TCP/IP connections only.

$sslcipher

SessObj.$sslcipher returns the name of the SSL cipher being used for the
current SSL connection or empty for a non-SSL connection. (Read-only)

$threadid

SessObj.$threadid is the thread ID of the current connection. (Read-only)

$threadsafe

SessObj.$threadsafe is kTrue if the client library was compiled as thread-safe.


(Read-only)

295

Chapter 9Server-Specific Programming

Session Methods

296

Method

Description

$changeuser()

SessObj.$changeuser({cUsername,cPassword}) changes the current


user. The new user will be connected to the database identified by the
$database property.

$characterset()

SessObj.$characterset() returns the name of the default character set


for the current connection.

$connectoption()

SessObj.$connectoption({iOption,vArgument}) specifies extra


connect options and affects the behavior of a connection. This
method may be called multiple times to set several options. Available
option constants can be found in the Catalog (F9) under
MYSQLDAM-ConnectOptions. For further details, refer to the
MySQL C API documentation for mysql_options().

$getdatatypemapping()

SessObj.$getdatatypemapping({lMappings}) retrieves a list of


Omnis-to-MySQL data type mappings currently in use by the session.
This list is formatted as described in the section below and is suitable
for re-assignment to the session via the $setdatatypemapping()
method if required. On successful retrieval of the list, $getdata
typemapping() returns kTrue, otherwise kFalse is returned.
$getdatatypemapping() can be called either before or after the session
has logged on.

$insertid()

SessObj.$insertid() returns the ID of an AUTO_INCREMENT


column generated by the most recently executed query. Use this
function after you have performed an INSERT query into a table that
contains an AUTO_INCREMENT field. $insertid() returns zero if
the previous query did not generate an AUTO_INCREMENT value,
or was not an INSERT/UPDATE

$ping()

SessObj.$ping() checks whether the connection to the server is


working. If it has gone down, an automatic reconnection is
attempted. $ping() returns kTrue if the connection is alive.

$query()

SessObj.$query(cSqlText) allows SQL statements not supported by


the MySQL prepared statement protocol to be executed directly on
the connection. At the time of writing, such statements include the
following administrative commands: GRANT, DROP
DATABASE/USER, HANDLER, TRUNCATE, ALTER
DATABASE/INDEX/USER, CREATE DATABASE/INDEX/USER,
USE, LOCK TABLES, UNLOCK TABLES, SAVEPOINT,
ROLLBACK TO SAVEPOINT, FLUSH, CACHE INDEX, LOAD
INDEX INTO CACHE, KILL CONNECTION/QUERY, RESET.
cSqlText can be either a single SQL statement or multiple statements
and can contain square bracket notation if required. Bind variables
are not supported; this functionality is provided by the statement
object. $query() returns kTrue on success, otherwise kFalse. Error
messages are returned via the session object.

MySQL
Method

Description

$queryinfo()

SessObj.$queryinfo() retrieves a string providing information about


the most recently executed query for any statement derived from the
session, but only for certain INSERT, UPDATE and ALTER
statements. For further information, refer to the MySQL C API
documentation for mysql_info().

$queryresult()

SessObj.$queryresult(lResult) allows the result set generated by a


previous call to $query() to be returned. lResult is a list variable
which is cleared and redefined from the columns of the result set. The
entire result set is placed into lResult and returned via a single call to
$queryresult(). $queryresult() performs limited data type conversion
on the various data types, recognising binary, integer and decimal
numbers, defaulting to Character for all other types. This method has
no effect if there is no result set pending on the session object.

$serverdebuginfo()

SessObj.$serverdebuginfo() instructs the server to write some debug


information to its error log. For this to work, the connected user must
have the SUPER privilege. The log file name can be specified when
the server is started by specifying --log-error[=filename]
on the command line.

$servershutdown()

SessObj.$servershutdown() asks the database server to shut down.


The connected user must have SHUTDOWN privileges. Note: no
further confirmation is sought before severing the connection and
shutting the server down. Returns kTrue if the server was
successfully shutdown.

$serverstatus()

SessObj.$serverstatus({cInfo}) returns information about the server's


current status, including the uptime in seconds and the number of
running threads, questions, reloads, and open tables.

$setdatatypemapping()

SessObj.$setdatatypemapping({lMappings}) sets the Omnis-toMySQL data type mappings for the session. The supplied list
contains a prioritised list of mappings for Omnis data types and
subtypes to their intended MySQL server data types. See the section
below on the format of the mapping list. $setdata typemapping() can
be used to map certain data type/subtypes to custom MySQL data
types, e.g. SET and ENUM types. This is also explained in the
section below. On successful execution of $setdatatypemapping()
kTrue is returned, otherwise kFalse is returned. SessObj.$setdata
typemapping() can be called either before or after the session has
logged on.

$sslset

SessObj.$sslset([cKey, cCert, cCA, cCAPath, cCipher]) is used for


establishing a secure connection using SSL. It must be called before
$logon(). cKey is the path name to the key file. cCert is the path
name to the certificate file. cCa is the path name to the certificate
authority file. cCAPath is the path name to a directory that contains
trusted SSL CA certificates in pem format. cCipher is a list of
permissible ciphers to use for SSL encryption. Any unused SSL
parameters will be treated as NULL.

297

Chapter 9Server-Specific Programming

Statement Methods
Method

Description

$columns()

StatObj.$columns({cTableName}). Returns information describing the


columns of the supplied table name. cTableName can be qualified with an
optional database name; [database.]tablename if required.
The DamInfoRow column returned by $columns() contains additional
information for each column described. The row is defined with the
following columns:
UniqueKey
MultipleKey
Unsigned
ZeroFill
Binary
AutoIncrement
Number
DefaultValue

$rpcprocedures()

kTrue if col is a unique index


kTrue if col is part of a compound index
kTrue if col has the UNSIGNED attribute
kTrue if col has the ZEROFILL attribute
kTrue if col contains binary (BLOB/TEXT) data
kTrue if col has the AUTO_INCREMENT attribute
kTrue if col contains numeric data
Returns the default value for col as char data

StatObj.$rpcprocedures([cOwner]) generates a result set containing the


names of stored procedures and functions which (optionally) were created by
the named user. The DamInfoRow column returned by $rpcprocedures()
contains additional information for each procedure described. The row is
defined with the following columns:
Type

Specifies whether the row describes a procedure or


function
Specific Name
The specific name of the procedure.
Language
The programming language contained within
the procedure.
SQL Data Access Describes data usage characteristics of the procedure.
Deterministic
kTrue if the procedure is deterministic, i.e. always
produces the same result for the same input parameters.
Security Type
Describes the permissions used when executing
the procedure.
Param List
Contains a comma separated list of input/output
parameters.
Returns
Describes the data type returned by a function.
Body
Returns the text content of the procedure.
Created
The date and time when the procedure was created.
Modified
The date and time when the procedure was last modified.
SQL Mode
Describes the SQL syntax supported by the procedure.
Comment
User comment added when the procedure was created.
Stored procedures and functions are not supported in versions of MySQL
prior to 5.0.

Logging on to MySQL
The MySQL DAM interfaces directly with the MySQL client library, therefore the way the
DAM logs on to the server is slightly different to the other Object DAMs.
298

MySQL
Specifically, the $logon() hostname parameter is taken as the server hostname or IP address.
The username and password parameters are supplied as normal.
As well as the parameters supplied to $logon(), there are some additional parameters which
you can set using the following session properties:
$port - The port number of the MySQL server
$database - The database name
$clientflags - Sets additional behavior for the logon
$socket - Specified if you do not want to use a TCP/IP connection
When logging on using the SQL Browser, default values are used when the Port and
Database fields are left blank.

Transactions
If you require transaction support with MySQL, your server needs to support BDB or
InnoDB table types. Manual transactions may only be made on tables of these types.
When creating tables, you need to specify the table type required if you do not want the
default type (MyISAM).
The following properties and methods apply to transactions. Use of these properties or
methods is equivalent to executing the SQL statements shown:
$begin()

SessObj.$begin() = Begin

$commit()

SessObj.$commit() = Commit

$rollback()

SessObj.$rollback() = Rollback

$transactionmode

SessObj.$transactionmode.$assign(SessionMode)
kSessionTranAutomatic: Autocommit = 1 (the default)
kSessionTranServer: Autocommit = 1
kSessionTranManual: Autocommit = 0

If you are not using InnoDB or BDB table types, you can achieve table locking using the
MySQL lock tables or unlock tables SQL commands. Refer to the MySQL
language reference for further details.

299

Chapter 9Server-Specific Programming

MySQL Data Type Mapping


Omnis to MySQL
The default data type mappings from Omnis to MySQL are shown below.
Omnis Date Type

MySQL Data Type

CHARACTER
Character n (n<=255)

VARCHAR(n)

National n (n<=255)

NATIONAL VARCHAR(n)

Character/National n (n<=65534)

TEXT

Character/National n
(65534<n<=10000000)

MEDIUMTEXT

NUMBER
Integer 64 bit

BIGINT

Integer 32 bit

INT

Short integer

TINYINT UNSIGNED

Number 0..14dp

DECIMAL(15,0..14)

Number floating dp

DOUBLE

Short number 0/2dp

DECIMAL(9,0/2)

DATE/TIME
Short date (all subtypes)

DATE

Short time

TIME

Datetime (#FDT)

DATETIME

OTHER

300

Boolean

BOOL

Picture

MEDIUMBLOB

List

MEDIUMBLOB

Row

MEDIUMBLOB

Object

MEDIUMBLOB

Binary

MEDIUMBLOB

Item reference

TINYBLOB

Sequence

INT UNSIGNED AUTO_INCREMENT


PRIMARY KEY

MySQL
Note that this is equivalent to the list returned by a call to $getdatatypemapping() on a
newly created session object:
OmnisType

OmnisSubtype

Parameter

MySqlType

char

simple

255

VARCHAR($)

char

national

255

NATIONAL VARCHAR($)

char

national

65534

TEXT

char

national

10000000

MEDIUMTEXT

integer

64 bit

BIGINT

integer

32 bit

INT

integer

shortint

TINYINT UNSIGNED

number

14dp

DECIMAL(15,$)

number

float

DOUBLE

number

2dpShortnum

DECIMAL(9,$)

boolean

BOOL

date

date2000

DATE

date

time

TIME

date

datetime

DATETIME

picture

MEDIUMBLOB

list

MEDIUMBLOB

row

MEDIUMBLOB

object

MEDIUMBLOB

binary

MEDIUMBLOB

itemref

TINYBLOB

Assigning a new mapping table using $setdatatypemapping()


If you need to make a change to the default Omnis to MySQL data type mappings, you
should probably base your new mappings on the default mappings obtainable by calling
$getdatatypemapping() and add/remove lines to the returned list as required before calling
$setdatatypemapping() to install the new mapping table.
There are a number of points to note regarding the format and processing of the list used by
these methods and these are discussed below.
Omnis subtype precedence
Note that where multiple occurrences of Omnis types appear in the list, the Omnis
subtype(s) should be specified in ascending numerical order, especially if you intend a
mapping to apply to all Omnis subtypes <= the supplied value. This is because when
searching for a match, the list is processed in order from the first entry to last- the search
301

Chapter 9Server-Specific Programming


ends at the first matching entry. The full list of acceptable data subtypes can be found in the
Omnis catalog (F9) and their text equivalents are shown in the OmnisSubtype column, as
summarised below:
Omnis constant
Character subtypes
kSimplechar
kNatchar
Integer subtypes
k32bitint
kShortint
k64bitint
Number subtypes
k0dp
k1dp
k2dp
k3dp
k4dp
k5dp
k6dp
k8dp
k10dp
k12dp
k14dp
kFloatdp
k0dpShortnum
k2dpShortnum
Datetime subtypes
kDate1900
kDate1980
kDate2000
kTime
kDatetime

Numeric value
(precedence)

Character equivalent
(OmnisSubtype)

0
1

simple
national

0
32
64

32 bit integer
shortint
64 bit integer

0
1
2
3
4
5
6
8
10
12
14
24
32
34

0dp
1dp
2dp
3dp
4dp
5dp
6dp
8dp
10dp
12dp
14dp
float
0dpShortnum
2dpShortnum

0
1
2
6
1000

date1900
date1980
date2000
time
Datetime

Note that where an Omnis type does not have a subtype (e.g. Binary), it is acceptable to
leave the subtype column blank.

302

MySQL
Parameter column
The Parameter value in the data type mapping list specifies the maximum length or size of
data to which the mapping will apply, e.g. a value of 255 specified for a character data type
signifies that that mapping will apply to Omnis character data with a length of <= 255
characters. You should therefore ensure that where there are multiple occurrences of the
same Omnis data type and subtype, these are entered in ascending order of parameter value.
The maximum size of an Omnis character/binary field is 10,000,000 bytes.
MySqlType column
The MySqlType value specifies the string which will be returned by session.$createnames()
when that row matches the supplied Omnis data type & subtype. This can be (but is not
restricted to) any string which constitutes a valid MySQL column type, e.g.
SET(One,Two,Three,Four).

Where a $ character is used as part of the MySQL type, the appropriate length or scale
attribute will be substituted when $createnames() is called.
For valid MySQL data type assignments, the DAM also uses the data type mapping table to
map outgoing bind variables to their corresponding MySQL column types.
Example applications of $setdatatypemapping()
The intended use of $setdatatypemapping() is to allow schema columns to conditionally
map to custom MySQL data types, not implemented by default, e.g. the SET, ENUM,
GEOMETRY and YEAR types and also to allow extra type qualifiers to be added, such as
UNSIGNED, PRIMARY KEY, AUTO_INCREMENT, etc.
To get $createnames() to return one of these types, you might for example isolate a specific
character string length and add a data type mapping for your new type.
Then whenever $createnames() encounters a string of that specific length, the mapping to
your new type will occur. If you want to implement the SET data type, you could insert a
new mapping entry between the first and second default entries, adjusting the length
parameters as shown below:
char

simple

254

VARCHAR($)

char

simple

255

SET(One,Two,Three,Four)

char

national

255

NATIONAL VARCHAR($)

Alternatively, you could dedicate the national character subtype for your custom data
types, leaving the simple character subtype for standard character mappings.

303

Chapter 9Server-Specific Programming

MySQL to Omnis
The following mappings are hard-coded and cannot be altered.
MySQL Column Type

Range

OmnisType/
Subtype

NUMBER
Boolean

BIT/BOOL/TINYINT(1)
TINYINT UNSIGNED
TINYINT
SMALLINT
MEDIUMINT
INT/INTEGER
BIGINT
FLOAT
DOUBLE/REAL
DEC/DECIMAL/NUMERIC
DATE/TIME
DATE
DATETIME
TIMESTAMP
TIME
YEAR
CHARACTER
CHAR
VARCHAR
TINYTEXT
TEXT
MEDIUMTEXT
LONGTEXT
ENUM
SET
BINARY
TINYBLOB
BLOB
MEDIUMBLOB
LONGBLOB

304

(0..+255)
(-128..+127)
2^16 (-32768..+32767)
2^24 (-8388608..+8388607)
2^32 (-2147483648..+2147483647)
2^64 (-2^63..+2^63-1)

Short integer
Short number 0dp
Integer 32 bit
Integer 32 bit
Integer 32 bit
Integer 64 bit
Num floating dp
Num floating dp
Num 0..14dp
Datetime (#FDT)
Datetime (#FDT)
Datetime (#FDT)
Datetime (#FDT)
Integer 32 bit

1 to 255 bytes fixed


0 to 255 bytes varying
255 (2^8 1) bytes
65535 (2^16 1) bytes
16777215 (2^24 1) bytes
4294967295 (2^32 1) bytes

Character
Character
Character
Character
Character
Character
Character
Character

255 (2^8 1) bytes


65535 (2^16 1) bytes
16777215 (2^24 1) bytes
4294967295 (2^32 1) bytes

Binary
Binary
Binary
Binary

PostgreSQL

MySQL Troubleshooting
The following points may help in resolving programming issues encountered using MySQL
session and statement objects. For additional updated trouble shooting issues, refer to the
readme file which accompanies your installation media.
$sqlstripspaces has no effect for MySQL sessions. MySQL automatically strips trailing
spaces from data inserted into CHAR and VARCHAR columns. Character data
returned from the server will already be stripped of trailing spaces.
MySQL 4.1 does not support chunking of fetched (output) LOB data (TEXT and
BLOB types). Chunking of input LOB data is supported.
$rowcount will be 1 following execution of a SELECT, SHOW or EXPLAIN
statement. This is because MySQL cannot determine this value until the final row has
been fetched.
The MySQL DAM is compatible with MySQL Server version 4.1 and later. Prior to
Omnis Studio version 4.1, connection is only possible to a commercial version of
MySQL Server (i.e. MySQL pro or classic). Later versions of Studio do not have
this restriction.
Further troubleshooting notes, how-tos and tips can be found on the Omnis website at:
www.omnis.net/technotes

PostgreSQL
This section contains the additional information you need to access a PostgreSQL database,
including server-specific programming, data type mapping to and from PostgreSQL, as well
as troubleshooting. For general information about logging on and managing your database
using the Omnis SQL Browser, refer to the earlier parts of this manual.
For additional information on changes to the PostgreSQL DAM, refer to the readme file
which accompanies your installation media.

PostgreSQL Client Libraries


This section discusses the PostgreSQL client library, which must be present on the library
search path before the PostgreSQL DAM can be used.

Win32 platforms
For Win32 platforms, the library search path includes the Windows\System32 folder or any
location in the PATH environment variable, including the folder containing omnis.exe. The
Win32 client library is named libpq.dll.

305

Chapter 9Server-Specific Programming

Linux and OS X platforms


The Unix ports of the PostgreSQL DAM look for libpq.so or liqpq.dylib under Linux and
OS X respectively.
In most cases the library present on your system will be labelled according to the version
you have installed. For example on Linux, libpq.so might be a symbolic link to the target
library libpq.so.5.0. A detailed directory listing shows this relationship, e.g.
12
117338

2007-01-15

10:20

libpq.so -> libpq.so.5.0

2007-01-15

10:20

libpq.so.5.0

Under Linux and OS X therefore, it is essential that the target library and symbolic link to it
both exist either in the library search path or in the same folder as the Omnis executable.

OS X only
The client library supplied with Omnis Studio is built as a Universal Binary- meaning that it
is compatible with both Mac-Intel and Mac-PPC architectures. If you substitute this library
for one obtained e.g. from the PostgreSQL website, please note that the replacement library
may support a single architecture, restricting use of the DAM to that architecture only.
You can determine the architecture(s) supported by a Mach-O dynamic library using the
file terminal command. For example:
>

file libpq.5.0.dylib

libpq.5.0.dylib: Mach-O universal binary with 2 architectures


libpq.5.0.dylib (for architecture i386): Mach-O dynamically linked
shared library i386
libpq.5.0.dylib (for architecture ppc): Mach-O dynamically linked
shared library ppc

306

PostgreSQL

Properties and Methods


In addition to the base properties and methods documented in the SQL Programming
chapter, the PostgreSQL DAM provides the following additional features.

Session Properties
Property

Description

$maxvarchar

Defines the maximum size above which- Omnis Character fields will
be mapped to TEXT type instead of VARCHAR. The default value
for this property is 2000.

$database

Used to set the additional dbname logon parameter. If not specified,


defaults to be the same as the user name.

$service

Service name to use for additional parameters. It specifies a service


name in pg_service.conf that holds additional connection
parameters. This allows applications to specify only a service name so
connection parameters can be centrally maintained.

$protocolversion

(Read-only)This property reports the communication protocol version


supported by the client library. DAMPGSQL requires version 3.0 or
higher in order to work correctly.

$backendpid

(Read-only) Following logon, this property holds the process ID of the


backend server process handling the connection. This may be useful
for debugging purposes since the PID is reported in NOTIFY
messages.

$port

Used to set the additional port logon parameter. This property has a
default value of 5432.

$socket

(Read-only) Following logon, this property holds the file descriptor


number of the connection socket to the server. A valid descriptor will
be greater than or equal to 0; a result of -1 indicates that no server
connection is currently open.

$options

Used to specify additional text to be appended to the logon connection


string. One or more parameter settings can be added, separated by
spaces. The options string is limited to 255 characters.
Discussion of advanced connection options is beyond the scope of this
text but an example string might be:
Do sess.$options.$assign(options='-c geqo=off' sslmode=require)

$logontimeout

Maximum wait for a connection, in seconds. Zero implies wait


indefinitely. The default timeout is set to 15 seconds. A timeout of less
than 2 seconds is not recommended.

$timezone

Character string representing the time zone to be appended on to bind


variables being inserted into TIMETZ and TIMESTAMPTZ columns.

307

Chapter 9Server-Specific Programming


Property

Description
The default time zone is +00 but $timezone will accept any
character string (80 characters max).

308

$usetimezone

If set to kTrue, the value contained in $timezone is appended to


outgoing Time and Datetime bind variables. This property also affects
the text returned by $createnames() for Time and DateTime columns.
$timezone will be ignored during insert/update of TIMESTAMP &
TIME columns

$serializable

If set to kTrue, manual transactions will be created using the


Serializable isolation level. When set to kFalse (the default), manual
transactions will be created using the Read Committed isolation level.

$readonly

If set to kTrue, manual transactions will be created using read-only


access mode. When set to kFalse (the default), transactions will have
read/write access.

$schema

The optional schema name to be prepended to table names. Used by


the SQL Browser when performing SELECTs. The default schema
name is an empty string.

$numericprecision

Defines the precision used by $createnames() when mapping Omnis


number (dp) columns to the NUMERIC type. Cannot be set lower than
the default value: 15.

$sequencetoint

If set to kTrue, the Omnis Sequence type is mapped to INTEGER. If


set to kFalse (the default), the Sequence type is mapped to SERIAL.
Affects $createnames() and outward bind variables.

$char38touuid

If set to kTrue, Omnis character types of field length 38 are mapped to


the PostgreSQL 8.3 Universally Unique Identifier type (UUID).

$char39tooid

If set to kTrue, Omnis character types of field length 39 are mapped to


the PostgreSQL Object Identifier type (OID).

PostgreSQL

Session Methods
Method

Description

$connectstatus()

Returns a PGSQLDAM Connection Status constant representing the


current state of the connection to the database server, or empty if not
connected.

$escapebinary()

Returns a text-escaped representation of the supplied binary


variable, suitable for use in an SQL statement as a quoted string
literal. The returned string does not include the quotes.

$getssl()

Returns qtrue if the connection is using SSL, qfalse otherwise.


An optional list parameter can also be passed to return additional
information. Currently, the SSL type and version are returned.

$transactionstatus()

Returns the current in-transaction status of the server. The status can
be kPgSqlTranIdle (currently idle), kPgSqlTranActive (a
command is in progress), kPgSqlTranInTrans (idle, in a valid
transaction block), or kPgSqlTranINError (idle, in a failed
transaction block). kPgSqlTranUnknown is reported if the
connection is bad. kPgSqlTranActive is reported only when a query
has been sent to the server and not yet completed.

$parameterstatus()

Looks up a current parameter setting of the server. Supported


(string) parameters include server_version, server_encoding,
client_encoding, is_superuser, session_authorization,
DateStyle, TimeZone, integer_datetimes, and
standard_conforming_strings. For a full list, refer to the API
documentation for the PQparameterStatus function.

$reset()

Resets the communication channel to the server.


This function will close the connection to the server and attempt to
re-establish a new connection to the same server, using all the same
parameters previously used. This may be useful for error recovery if
a working connection is lost.

$cancel()

Requests that the server abandon processing of any transactions


pending on the session. Successful execution is no guarantee that the
request will have any effect, however. If the cancellation is effective,
the current command(s) will terminate early and return an error
result.

$addcustomtype()

Creates a custom data type mapping for specified Omnis character


subtypes. Intended to allow creation and insertion into PostgreSQL
309

Chapter 9Server-Specific Programming


Method

Description
8.3 enum and xml columns.

310

$clearcustomtypes()

Removes previously created custom data type mappings.

$lobimport()

$lobimport(cFilename[, iOid]) Imports the contents of the specified


operating system file into the database and returns the new OID on
success, zero otherwise. If a specific OID value is desired, it may be
passed in via parameter 2. Must be called within a manual
transaction block.

$lobexport()

$lobexport(cFilename, iOid) Exports the object specified by iOid


into the specified operating system file. Must be called within a
manual transaction block. Returns kTrue on success.

$lobcreate()

$lobcreate([iOid]) Creates a new large object and returns the new


OID value on success, zero otherwise. If a specific OID value is
desired, it may be passed in via parameter 1. Must be called within a
manual transaction block.

$lobunlink()

$lobunlink(iOid) Removes the specified object from the database


and unlinks the Object Identifier, effectively deleting the object.
Must be called within a manual transaction block. Returns kTrue if
the object was successfully unlinked.

$lobopen()

$lobopen(iOid[, bReadOnly]) Opens the specified large object for


reading/writing and returns the large-object descriptor which is only
valid for the duration of the current transaction. If bReadOnly is
specified (kTrue), a read-only snap shot of the object is taken as it
was at the start of the transaction.

$lobwrite()

$lobwrite(iDesc, xBinary[, iSize]) Writes the supplied binary data to


the specified large-object descriptor, returning the number of bytes
that were written on success, or -1 on failure. By default, the entire
binary field is written unless iSize is specified.

$lobread()

$lobread(iDesc, xBinary[, iSize]) Reads the large object specified by


iDesc into xBinary and returns the number of bytes read on success,
or -1 on failure. If specified, iSize bytes are allocated and read from
the large object. If omitted, $blobsize bytes are allocated/requested.

$lobseek()

$lobseek(iDesc, iOffset, iWhence) Moves the read/write pointer


within an open large object by iOffset bytes. iWhence governs how
the offset is interpreted; kPgSqlSeekSet specifies an absolute offset
from the start of the object, kPgSqlSeekCur specifies an offset from
the current position, kPgSqlSeekEnd specifies an offset from the end
of the object. Returns the new location on success, or -1 on failure.

$lobtell()

$lobtell(iDesc) Returns the current position of the read/write pointer


within the large object specified by iDesc, or -1 on failure.

PostgreSQL
Method

Description

$lobtruncate()

$lobtruncate(iDesc, iSize) Resizes the specified large object to iSize


bytes. If iSize is larger than the current size, the large object is
padded with null bytes. Returns kTrue on success, kFalse otherwise.

$lobclose()

$lobclose(iDesc) Explicitly closes the specified large-object


descriptor. Any large-object descriptors that remain open at the end
of a transaction will be closed automatically. Returns kTrue on
success, kFalse otherwise.

Statement Properties
Property

Description

$sqlstate

(Read only) On error, this property contains the five-character SQLSTATE


associated with the $nativeerrortext. Refer to the PostgreSQL reference manual
for a full list of SQLSTATEs.

Logging on to PostgreSQL
In addition to the hostname, username and password parameters provided by the $logon()
method, the PostgreSQL DAM provides several session properties which enable additional
logon parameters to be set. These should be set before calling $logon().
$database is used to specify the dbname connection parameter.
$port is used to specify the port connection parameter.
$logontimeout is used to specify the connect_timeout parameter.
$options is used to specify further optional connection parameters.
$service is used to specify a service (filename) to use for additional parameters.

Metadata Functions
$indexes()
The DamInfoRow for $indexes() is defined with a single column containing the SQL text
used to define the index.
$tables()
The PostgreSQL DAM implements $tables() slightly differently. In particular- only the
kStatementServerTable and kStatementServerView parameters are supported. This is
because the processes for querying tables are incompatible with those for querying views.
(kStatementServerAll defaults to kStatementServerTable).

311

Chapter 9Server-Specific Programming


The DamInfoRow for $tables() is defined with three Boolean columns with additional
information on the table or view: HasIndexes, HasRules & HasTriggers.

Transactions
PostgreSQL supports two transaction isolation levels: Read Committed (the default) and
Serializable. Using Read Committed mode, a statement can only see rows that were
committed before the current transaction began. Using Serializable mode, all statements in
the current transaction can only see rows that were committed before the first query or datamodification statement was executed in this transaction.
Transactions can also be instantiated as read-only if required. This enables significant
performance improvements for read operations. When a transaction is read-only, the
following SQL commands are disallowed: INSERT,UPDATE,DELETE and COPY FROM
if the table they would write to is not a temporary table; all CREATE,ALTER and DROP
commands; COMMENT,GRANT,REVOKE,TRUNCATE,EXPLAIN ANALYZE and
EXECUTE if the command they would execute is among those listed. Please refer to the
PostgreSQL documentation on transactions for further details.
When using manual transaction mode (kSessionTranManual), the transaction isolation level
can be switched between Read Committed and Serializable using the $serializable session
property.
The access mode can be changed using the $readonly session property.
The PostgreSQL DAM treats the kSessionTranAutomatic and kSessionTranServer
transaction modes identically. In either of these modes the server automatically begins and
commits read/write transactions.

Remote Procedure Calls


Note that PostgreSQL does not support the concept of stored procedures but supports
functions instead. This has a few implications as described below.
$rpcprocedures(). The DamInfoRow returned by $rpcprocedures is defined with the
following columns:

312

Language

The implementation language or call interface for this function.

IsAgg

kTrue if this is an aggregate function.

SecDef

kTrue if this function is a security definer (i.e. a "setuid" function).

IsStrict

kTrue if this is a "strict" function. Strict functions must be prepared to


handle null inputs.

RetSet

kTrue if the function returns a result set (i.e. multiple values of the
specified data type).

PostgreSQL
Volatile

Indicates whether the function result depends only on its input arguments,
or is affected by outside factors. It is i for "immutable" functions, which
always deliver the same result for the same inputs. It is s for "stable"
functions, whose results (for fixed inputs) do not change within a scan. It
is v for "volatile" functions, whose results may change at any time, that
have side-effects for other functions or tables or functions which cannot
otherwise be optimised.

Source

Indicates how the function should be invoked. It might be the actual


source code of the function for interpreted languages, a link symbol, a file
name, or just about anything else, depending on the implementation
language/call convention.

$rpc(). Calling $rpc() is similar to executing a SQL SELECT statement of the form:
SELECT * from proc_name (param1,

param2, )

with the exception that $rpc() will also set any InputOutput or Output parameters.
Any return value generated by the function will be available via $rpcreturnvalue although in
the case where the function generates a result set, it may be preferable to retrieve the entire
set by calling $fetch(). The value returned by $rpcreturnvalue is also returned as the first
row of this result set.

313

Chapter 9Server-Specific Programming

PostgreSQL Data Type Mapping


Omnis to PostgreSQL
Omnis Data Type

PostgreSQL Data Type

CHARACTER
Character/National n (n<=$maxvarchar)

VARCHAR(n)

Character/National n (n>$maxvarchar)
Character(38)
NUMBER

TEXT
UUID [3]

Integer 64 bit

BIGINT

Integer 32 bit

INTEGER

Short integer

SMALLINT

Number 0..14dp

NUMERIC(15[1] ,0..14)

Short number 0/2dp

NUMERIC(15[1],0/2)

Number floating dp

DOUBLE PRECISION

DATE/TIME
Short date (all subtypes)

DATE

Short time

TIME /TIMETZ*

Datetime (all subtypes)

TIMESTAMP /TIMESTAMPTZ*

OTHER
Boolean

BOOLEAN

Sequence

SERIAL/INTEGER [2]

Picture

BYTEA

List

BYTEA

Row

BYTEA

Object

BYTEA

Binary

BYTEA

Item reference

BYTEA

[1] Numeric precision for Number (dp) columns uses the value of $numericprecision.
[2] The mapping used for the Omnis Sequence type depends on the value of $sequencetoint.
[3] This mapping occurs only if $char38touuid is set to kTrue
*Time zone data types are used when session.$usetimezone is set to kTrue

314

PostgreSQL

PostgreSQL to Omnis
PostgreSQL Data Type

Description

Omnis Data Type

INT2/SMALLINT

-32768 to +32767

Integer 32 bit

INT/INT4/INTEGER

-2147483648 to +2147483647

Integer 32 bit

INT8/BIGINT

-2^63 to +2^63-1

Integer 64 bit

SERIAL

1 to 4294967296

Integer 32 bit

SERIAL8/BIGSERIAL

1 to 2^64

Integer 64 bit

FLOAT4/FLOAT/REAL

1E-37 to 1E+37

Number floating dp

DOUBLE/FLOAT8

1E-307 to 1E+308

Number floating dp

NUMERIC

Numbers with max precision 1000

Number floating dp (1)

MONEY

-21474836.48 to +21474836.47

Number 2dp

DATE

Dates only

Short date

TIMESTAMP/TIME

Timestamp/time without time zone

Datetime (#FDT)

NUMBER

DATE/TIME

TIMESTAMPTZ/TIMETZ Timestamp/time with time zone

Character

INTERVAL

Flexible format time interval

Character

CHAR

Blank-padded characters with size limit

Character

VARCHAR

Variable length characters with size limit

Character

TEXT

Variable length characters with no size limit Character

BOOLEAN/BOOL

{'f', 'false', 'n', 'no', '0', 't','true','y','yes','1'}

CHARACTER

Boolean

CIDR, INET, MACADDR Strings containing address information

Character

UUID

Universally Unique Identifier

Character 36

ENUM

Custom enumerated types

Character 64

XML

Extensible Markup Language content

Character

OTHERS (including, but not limited to)


BYTEA, BIT, VARBIT, BOX, CIRCLE,
POINT, LINE, PATH, POLYGON, LSEG
(1)

Binary

DAM will map decimal values to the Omnis Number dp data type where column scale is <=14

315

Chapter 9Server-Specific Programming

PostgreSQL 8.3 Data Types


Support for the following data types is available in Omnis Studio 4.3.1 and above.
UUID
The PostgreSQL DAM is able to read and write Universally Unique Identifiers. An example
of a UUID in standard form might be:
a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 (36 characters)

but the DAM also accepts UUIDs formatted without hyphens and/or encapsulated using
curly braces.
Output from UUID columns is always in the standard form.
To allow input binding of UUIDs and to make $createnames() return UUID types, it is
necessary to set $char38touuid to kTrue. Once set, the Omnis Character 38 data subtype
maps to UUID.
Note: there is no facility either in the PostgreSQL client library or in the DAM to create
UUID values. This must be implemented by the Omnis application.
ENUM
Enumerated types are created by executing CREATE TYPE statements, for example:
Do statObj.$execdirect("CREATE TYPE mood AS ENUM ('sad',
'ok', 'happy')") Returns #F ;;creates the enumerated type
To make Omnis map certain character sub types to ENUMs, the $addcustomtype() method
is provided.
The following example maps the Omnis Character 2001 data subtype to the mood
enumerated type:
Do sessObj.$addcustomtype(2001,'mood') Returns #F

Once set, this mapping affects the text generated by $createnames() as well as input binding.
To clear previously defined enumerated type mappings, the $clearcustomtypes() method is
provided.
XML
The $addcustomtype() method can also be used to force an Omnis Character subtype to map
to the XML data type, for example:
Do sessObj.$addcustomtype(10001,'xml') Returns #F
As above, this mapping affects the text generated by $createnames() as well as input
binding and remains in effect until $clearcustomtypes() is called.

316

PostgreSQL

Large Object Support


As of Omnis Studio 5.1.1, the PostgreSQL DAM supports additional session object
methods for manipulating large objects stored in the database.
The methods; $lobimport(), $lobexport() and $lobunlink() complement their SQL
equivalents (lo_import(), lo_export() & lo_unlink()) with the exception that the client-side
methods operate on files in the client machines file system. The SQL functions operate on
files in the database servers file system. In other respects, the operation of these methods is
comparable:

$lobimport() creates a large object and imports data into it from a local file.

$lobexport() retrieves data from a large object and writes it to a local file.

$lobunlink() removes a large object from the database.

There is an additional client-side method for creating a large object:

$lobcreate() creates a new (empty) large object and returns the OID value.

The large objects are identified by their OID values, which can subsequently be stored and
retrieved in database Oid columns in a similar fashion to standard integers.
Once created, the following methods can be used to manipulate data inside large objects:

$lobopen() opens a large object (OID) and returns a large object descriptor.

$lobclose() closes a large object descriptor.

$lobread() reads zero or more bytes from a descriptor into a Binary variable.

$lobwrite() writes zero or more bytes to a descriptor from a Binary variable.

$lobseek() repositions the read/write pointer within a large object.

$lobtell() reports the current pointer position within a large object.

$lobtruncate() resizes a large object to the desired size (in bytes).

To use these methods, it is important to note that large object operations must be performed
within a single transaction, i.e. in manual transaction mode. Any open large object
descriptors are automatically closed upon $commit(). For example:
Do cSess.$transactionmode.$assign(kSessionTranManual)
Do cSess.$begin()
Do cSess.$lobcreate() Returns lOid
;; create new oid
Do cSess.$commit()
Do cSess.$begin()
Do cSess.$lobopen(lOid) Returns fileDesc
Calculate lBinary as 'Some Unicode character data'
Do cSess.$lobwrite(fileDesc,lBinary) Returns lNumBytes ;;write
data into the large object
Do cSess.$lobseek(fileDesc,8,kPgSqlSeekSet) Returns lFilePos

317

Chapter 9Server-Specific Programming


;;move the read/write pointer to byte 8/character position 3
Do cSess.$lobread(fileDesc,lCharValue) Returns lNumBytes ;;=> 'me
Unicode character data'
Do cSess.$commit() ;; commit closes the descriptor

For further information on the behavior of these methods and the parameter values that may
be applied, please refer to the Session Methods section above.

PostgreSQL Troubleshooting
The following points may help in resolving programming issues encountered using
PostgreSQL session and statement objects.
$rpcparameters(). When calling $rpcparameters(), the DAM uses defaults for the
column precision and/or scale since this information is not provided by the pg_proc
system table.
For this reason, the API may report parameter-matching problems when calling certain
functions and the list (passed to $rpcdefine()) may need to be manually coerced.
Error Messages. The following additional error messages may be returned via the
session or statement $errortext property:
"Native error text could not be retrieved". No connection currently exists to the server
or there is no message corresponding to the current error code.
"Unsupported client protocol version". The protocol version reported by the client API
is too low. The DAM cannot use this version and you should upgrade to a newer
version of the client library. Use the PostgreSQL access library supplied with Omnis
Studio.
"Client or interface function not available". The most likely cause of this error is that
the client library (or one of its dependencies) was not found and has not been loaded.
Can also occur if the client library being used does not provide a required interface
function.
"server closed the connection unexpectedly. This probably means the server terminated
abnormally before or while processing the request." This error can occur when logging
on with a username other than postgres. The client library uses the username for the
database name unless the database name is specified. Set $database to the required
database name (e.g. postgres) and try again.
Linux Terminal Messages. On Linux, NOTICE and/or WARNING messages are sent
to stderr, (normally the terminal window behind Omnis). To avoid these, refer to the
server configuration parameter: client_min_messages and set his to a higher level.
Chunking and Batch Fetching. Chunking of large character/binary data is not handled
by DAMPGSQL but is handled automatically by the API. Such data is effectively
returned to the DAM as single chunks. $lobthreshold , $lobchunksize and $blobsize
therefore have no effect.
318

SQLite
Batch fetching of data is also not handled by DAMPGSQL. The API automatically
manages transfer of the data and presents the DAM with the entire result set. Hence
setting $batchsize has no effect.
Further troubleshooting notes, how-tos and tips can be found on the Omnis website at:
www.omnis.net/technotes

SQLite
This section contains the additional information you need to access a SQLite database, a
very popular database which is embedded into a whole range of applications on desktop and
mobile devices. The code for SQLite is in the public domain and is thus free for use for any
purpose, commercial or private.
SQLite implements a self-contained, server-less, zero-configuration, transactional SQL
database engine. Unlike most other SQL databases, SQLite does not have a separate server
process. SQLite reads and writes directly to a disk file which can contain multiple tables,
indices, triggers, and views. For more information about SQLite and to download it, please
go to the website: www.sqlite.org (portions of this text are taken from the SQLite website).
The SQLite DAM uses the SQLite v3.0 API which uses a different file format to the v2.8
API. Existing v2.8 datafiles must be converted for use with v3.0. See
http://www.sqlite.org/version3.html) for more details about SQLite3.
This section contains the additional information you need to access a SQLite database,
including server-specific programming, trouble-shooting and data type mapping to and from
the database. For additional information on changes to the SQLite DAM, refer to the
readme file which accompanies your installation media.

Server-specific Programming
Logging on to SQLite
To connect using the SQLite DAM, create an object variable of subtype SQLITESESS.
You connect to a SQLite data file using the $logon() method. The hostname parameter
should be the full path to the data file.
SQLite does not require a username or password, but you can specify a session name that
will appear in the SQL Browser and in the Notation Inspector under $sessions.
SQLite expects a DOS-style pathname under Windows and an absolute POSIX-style path
under OS X and Linux. For example:
Do mySession.$logon(C:\mydata\mydatafile.db,,,session1)
Returns #F ;; on Windows
Do mySession.$logon(/Users/MyUser/mydatafile.db,,,session1)
Returns #F ;; on OS X / Linux

319

Chapter 9Server-Specific Programming


Additionally, you can force SQLite to create the specified data file if it does not exist. To do
this, set the $opencreate session property to kTrue before logging on.
To open a read-only connection, set the $readonly session property to kTrue before logging
on. (It is not possible to create a data file if the connection is read-only).
If the hostname is ":memory:", then a private, temporary in-memory database is created for
the connection. This in-memory database will be deleted when the database connection is
closed. Filenames beginning with : should be considered reserved for future SQLite
extensions and avoided to remove ambiguity. For in-memory databases, $version will be set
to :memory: following $logon().
If the hostname is an empty string, then a private, temporary on-disk database will be
created. This private database will be automatically deleted as soon as the database
connection is closed. For temporary databases, $version will be set to :temporary:
following $logon().
For standard data file connections, $version is read directly from the file header information
and reflects the file format version that the data file supports.

Transaction Support
SQLite supports both automatic and manual SQL transactions.
To invoke manual transaction mode, the $transactionmode session property should be set to
kSessionTranManual.
In this mode you must commence each transaction by calling the $begin() session method
and terminating each transaction either by calling $commit(), $rollback(), by switching back
to kSessionTranAutomatic or by logging off.
The SQL text that is submitted each time $begin() is called may be augmented using the
$transactiontype session property as shown below. The different transaction types affect the
way in which SQLite acquires row locks on tables:
$transactiontype

Resulting SQL
text

Meaning

kSQLiteTranDeferred

BEGIN

No locks are acquired on the database until


the database is first accessed

kSQLiteTranExclusive

BEGIN
EXCLUSIVE

EXCLUSIVE locks are acquired on all


databases as soon as the BEGIN command
is executed

kSQLiteTranImmediate

BEGIN
IMMEDIATE

RESERVED locks are acquired on all


databases as soon as the BEGIN command
is executed

The $commit() and $rollback() methods, invoke the COMMIT and ROLLBACK
commands respectively.
320

SQLite
$commitmode and $rollbackmode are set to kSessionCommitClose and
kSessionRollbackClose respectively for the SQLite DAM. Statement objects are closed
upon $commit() / $rollback(). Any pending result set is discarded and the statement is
returned to its prepared state ready for re-execution if desired.

Incremental BLOB I/O


SQLite supports incremental Input/Output to BLOB columns in database tables. This means
that you effectively bind a placeholder for the BLOB at bind time, then write the data to it
later. Similarly, you can open a handle to a BLOB which already exists in the database and
read/modify its contents without the need to perform a SELECT statement.
To create a placeholder for a BLOB, you should bind the binary variable inside the SQL
statement as normal, but set its contents to #NULL. On execution, this creates a zero-blob
of size $blobsize- bytes padded with zeros.
The session object provides several methods for accessing and modifying BLOBs:
$blobopen()
Opens a handle to a BLOB column, identified by its database name, table name,
column name and row number, optionally as read-only
$blobclose()
Closes a BLOB handle; you have to close any BLOB handles opened during the
session, but any handles left open when the session ends are closed automatically
$blobcloseall()
Closes all BLOB handles
$blobbytes()
Returns the size in bytes that was allocated to a BLOB column when it was created
$blobhandles()
Returns a list of all open BLOB handles including the corresponding database, table
name, column name and row number
$blobreopen()
Moves a BLOB handle to a new row within the same table
$blobwrite()
Writes binary data to a BLOB column
$blobread()
Reads binary data from a BLOB column
See the Session Methods section for more details and syntax for these methods.

321

Chapter 9Server-Specific Programming

Session Properties

322

Property

Description

$blobsize

The default value for $blobsize is set at 32KB for the SQLite DAM
since this property is used routinely when creating empty BLOB
columns for use with incremental input/output methods.

$opencreate

If kTrue, the data file specified at $logon() will be created if it does not
exist. If kFalse (the default), an error will be generated if the data file is
not found.

$readonly

If kTrue, the connection will be opened in read-only mode. All attempts


to write to the data file will fail with an error. If kFalse (the default),
read and write operations are permitted.

$transactiontype

Specifies the locking behavior for manual transactions. This is one of


the following constants:
kSQLiteTranImmediate,
kSQLiteTranExclusive or
kSQLiteTranDeferred (the default).

SQLite

Session Methods
Method

Description

$blobbytes()

$blobbytes(iBlobHandle) returns the size in bytes that was allocated to


a BLOB column when it was created

$blobclose()

$blobclose(iBlobHandle) closes a BLOB handle. You should close any


BLOB handles opened during the session. Any handles left open when
the session ends are closed automatically however. Always returns
kTrue

$blobcloseall()

$blobcloseall() closes all BLOB handles. This method always returns


kTrue

$blobhandles()

$blobhandles(lHandleList ) returns a list of all BLOB handles including


their corresponding database, table names, column names and row
numbers. Aborted/invalid handles are shown with a row number set to
zero. Returns kTrue on success, otherwise kFalse

$blobopen()

$blobopen(cDatabase, cTable, cColumn, iRow [,bReadOnly]) opens a


handle to a BLOB column, identified by its database name, table name,
column name and row number, optionally as read-only. Returns a
BLOB handle on success or zero on failure. The SQLite DAM numbers
BLOB handles incrementally starting from 1001

$blobread()

$blobread(iBlobHandle, xBinary [,iSize ,iOffset]) reads binary data


from a BLOB column into the supplied binary variable. If iSize is
omitted, the value of $blobsize is assumed

$blobreopen()

$blobreopen(iBlobHandle, iRow) moves a BLOB handle to a new row


within the same table. If iRow exceeds the number of rows in the table,
this invalidates the handle. Only the row number can be modified. To
change the database, table name or column name, a new handle should
be opened

$blobwrite()

$blobwrite() writes binary data to a BLOB column

$lastrowid()

$lastrowid() returns the rowid of the most recent successful INSERT


into the database from the current connection

$rowsmodified()

$rowsmodified() returns the total number of database table rows that


have been affected by INSERT, UPDATE and DELETE operations
since the connection was opened (includes all statement objects)

323

Chapter 9Server-Specific Programming

Data Type Mapping


Omnis to SQLite
The SQLite DAM creates custom data types in order to preserve information about Omnis
subtypes, notably: DATE(n) as well as PICTURE, LIST, ROW, OBJECT and
OBJECTREF. There are also single mappings for Omnis Character and National data,
implying that CHAR(n) and NCHAR(n) can store up to the maximum field length supported
by Omnis (10000000 characters). This is contrary to other relational databases which
impose a fixed size on such columns.
Although this greatly improves compatibility between Omnis and SQLite, if portability of
the data file is of concern, then it may be preferable to avoid using $createnames() /
$coltext() in favor of manual statements that use standard SQL types, e.g. VARCHAR(n),
DATE, TEXT and BLOB.
Omnis Data Type

SQLite Data Type

CHARACTER
Character n
National n

CHAR(n)
NCHAR(n)

NUMBER
Integer 64 bit
Integer 32 bit
Short integer
Number 0..14dp
Short number 0/2dp
Number floating dp

BIGINT
INTEGER
TINYINT
NUMERIC(15, 0..14)
NUMERIC(9, 0/2)
FLOAT

DATE/TIME
Short date 1900..1999
Short date 1980..2079
Short date 2000..2099
Short time
Datetime (all subtypes)

DATE(1900)
DATE(1980)
DATE(2000)
TIME
TIMESTAMP

OTHER
Boolean
Sequence
Picture
List
Row
Object
Object reference
Binary / other

324

BIT
INTEGER PRIMARY KEY (auto increments when
inserted as NULL)
PICTURE
LIST
ROW
OBJECT
OBJECTREF
BINARY

SQLite

SQLite to Omnis
The SQLite DAM recognizes several additional SQL data types in order to maximize
compatibility with externally generated data files as well as those generated by Omnis.
SQLite Data Type

Omnis Data Type

NUMBER
TINYINT

Short integer

INT, SMALLINT, INTEGER

Integer 32 bit

SEQUENCE, INT AUTO INCREMENT

Sequence

BIGINT

Integer 64 bit

FLOAT, REAL, DOUBLE

Number floating dp

NUMERIC(p,s), DEC(p,s), DECIMAL (p,s)

Short number s dp (p <=9, s=0 or 2)


Number s dp (p <= 15)
Number floating dp (p > 15)

DATE/TIME
DATE(1900)

Short date 1900..1999

DATE(1980)

Short date 1980..2079

DATE(2000)

Short date 2000..2099

DATE, TIMESTAMP, TIME

Date Time (#FDT)

CHARACTER
CHAR, VARCHAR, TEXT, CLOB,

Character

NCHAR, NVARCHAR, NATIONAL

National

OTHERS
BOOLEAN, BOOL, BIT
PICTURE
LIST
ROW
OBJECT
OBJECTREF
BINARY / other

Boolean
Picture
List
Row
Object
Object reference
Binary

325

Chapter 9Server-Specific Programming

Troubleshooting
The following points may help in resolving programming issues encountered using SQLite
session and statement objects.
For additional updated troubleshooting issues, refer to the readme file which accompanies
the installation media.
For a detailed explanation of the SQL syntax supported by SQLite, please refer the SQLite
website: www.sqlite.org
SQLite does not currently support dynamic creation of SQL stored procedures or
functions. The associated methods; $rpcprocedures(), $rpcparameters() & $rpc()
therefore return kFalse.
The SQLite API handles the transfer of binary data automatically. The $blobsize,
$lobchunksize and $lobthreshold properties are therefore ignored.
For performance reasons, journaling mode is set to PERSIST for the SQLite DAM. For
optimum performance, especially on Linux it may be desirable to turn off journaling,
(PRAGMA journal_mode = OFF). Note: in this mode however it will not be possible
to rollback manual transactions.
You may experience slow performance during certain INSERT operations. Each
INSERT and UPDATE operation is normally committed to the disk drive so as to
preserve integrity of the data in the event of a crash or power failure. Executing
"PRAGMA synchronous=OFF" tells SQLite not to wait for data to reach the disk
surface between writes which results in much faster performance. This risks data loss or
corruption in the event of a crash however. Alternatively, you can use manual
transaction mode (kSessionTranManual) to commit several INSERT operations at
once.

326

ODBC

ODBC
This section contains the additional information you need to access a database using ODBC
middleware, including server-specific programming, data type mapping, as well as
troubleshooting. For general information about logging on and managing your database
using the Omnis SQL Browser, refer to the earlier parts of this manual.

Properties and Methods


In addition to the base properties and methods documented in the SQL Programming
chapter, the ODBC DAM provides the following additional features.

Session Properties
Property

Meaning

$dbmsname

Once a session has been established this is the name of the


database that the object is connected to. This defaults after a
$logoff. (Read only)

$dbmsversion

Once a session has been established this is the version of the


database that the object is connected to. This defaults after a
$logoff. (Read only)

$defaultdatabase

When set, the session will attempt to log on to the database


specified. A change to $defaultdatabase must be made before
logging on, otherwise the change will not take effect until the
session is re-used. To stop using a default database for the session,
set $defaultdatabase to an empty string (the default value). This
property may not be supported by all DBMS vendors.

$drivername

Once a session has been established this is the name of the ODBC
driver that the object is using. This defaults after a $logoff. (Read
only)

$driverversion

Once a session has been established this is the version of the


ODBC driver that the object is using. This defaults after a $logoff.
(Read only)

$driverodbcversion

Once a session has been established this is the version of the


ODBC API that the driver supports. This defaults after a $logoff.
(Read only)

$infoaserror

If kTrue (the default), execution results that report


SQL_SUCCESS_WITH_INFO are reported as errors. If kFalse, the
DAM treats this the same as SQL_SUCCESS and ignores the
accompanying message. Studio 5.2 and later.

327

Chapter 9Server-Specific Programming

328

Property

Meaning

$logontimeout

The timeout in seconds for a $logon() call. The default is 15


seconds. A value of 0 represents no timeout. A value of 1 can
also be specified to indicate that the DAM should not attempt to
set a timeout value.

$programname

The name to be registered at the server for the process associated


with the session. By default, $programname is set to the current
library name. This property may not be supported by all DBMS
vendors: see the $useprogramname property.

$querytimeout

The timeout in seconds for a query. A value of 0 represents no


timeout, which is the default.

$trustedconnection

Supported values are kODBCIgnoreTrusted (the default,)


kODBCUseTrusted and kODBCNotTrusted. When a value of
kODBCUseTrusted is specified, the session attempts to log on to
the DBMS using a server trusted connection, for which the
$username and $password will be ignored.
When a value of kODBCNotTrusted is specified, the session
attempts to log on to the DBMS with an explicitly non-trusted
connection.
This property may not be supported by all DBMS vendors.
Note that to enforce trusted connections, it may be necessary to
disable server prompting by setting $uselogonprompt to kFalse.

$usefiledsn

If kTrue, the hostname specified at logon will be treated as a file


DSN. The default is kFalse. Not all drivers support the use of file
DSNs.

$uselogonprompt

Governs the use of logon prompts where there is insufficient


information to connect Can also used to force the ODBC
Administrator library to display a configuration dialogue when
connecting to File DSNs. $uselogonprompt accepts constant
values of: kODBCPromptNever (0), kODBCPromptComplete (1),
kODBCPromptAlways (2). And kODBCPromptDsnLess (3).
Not all drivers can support this feature.

$useprogramname

If kTrue, the session attempts to register $programname as the


process name when logging on to the server. This property may
not be supported by all DBMS vendors. Hence the default value
for $useprogramname is kFalse. For SQLServer, the program
name can be found in the sysprocesses table of the master
database.

ODBC
Property

Meaning

$usequalifiers

When set to kTrue, the DAM treats qualified table names as


owner.tablename. To prevent this, for instance when using a text
file driver, set $usequalifiers to kFalse. This property affects the
behaviour of the $columns(), $tables(), $indexes() & $results()
session methods.
$usequalifiers is ignored until the session logs on, at which time
the default value is determined and $usequalifiers is overwritten.

$nationaltowchar

Available only with the Unicode DAM. By default, Omnis Character and
National fields are mapped to the SQL_WCHAR, SQL_WVARCHAR
and SQL_WLONGVARCHAR data types. By setting $nationaltowchar
to kTrue only National fields will be mapped to these types (to the
equivalent server data types) and Character fields will be mapped to
SQL_CHAR, SQL_VARCHAR and SQL_LONGVARCHAR as
determined by the Omnis field length. Character fields mapped in this
way are subject to data loss/truncation where such fields contain Unicode
characters. When setting this property, please note that Unicode data
types usually have precision limits half that of their corresponding ANSI
data types. For example, this is 8000 for the SQL Server VARCHAR()
data type but 4000 for NVARCHAR().
$nationaltowchar affects both the text returned by the $createnames()
method and the binding of input parameters.

$datesecdp

For use with Microsoft SQL Server 2008 TIME and


DATETIMEOFFSET data types which include a scale parameter.
$datesecdp affects the string returned by $createnames() as well as input
binding. Defaults to 2 but valid values are in the range 0 to 7.

$defaultschema

For use with Microsoft SQL Server 2005 and later. $defaultschema
returns the schema name which owns tables created by the current user.
This should be used in place of username in methods such as $tables().
Assigning to this property invokes an ALTER USER statement which
changes the default schema for the user.

A number of additional session properties have been added to the ODBC DAM in Studio
4.3.1 to facilitate better understanding and control of cursors and transactions. Use of these
properties assumes that the session is logged-on and has been placed in manual transaction
mode (kSessionTranManual):

329

Chapter 9Server-Specific Programming

330

Property

Description

$autobegintran

(Read Only). This property always returns kTrue for


DAMODBC because the ODBC API implicitly starts
transactions, even in manual transaction mode.

$cursorsensitivity

(Read Only). This property returns kTrue if SQL cursors are


sensitive to changes made by other cursors within the same
transaction. kFalse is returned if results returned by cursors are
not sensitive to changes made by other cursors in the same
transaction.

$txncapability

(Read Only). Returns one of the constant values listed in the


Catalog under ODBCDAM-Transaction Types. Certain drivers
only support use of DML statements within transaction blocks
(SELECT, INSERT, UPDATE, DELETE). Others may ignore
or permit use of DDL statements (CREATE TABLE, DROP
INDEX, and so on) but may require the transaction block to be
committed immediately. kODBCTxnAll specifies that
transactions can contain DDL statements and DML statements
in any order.

$multipletransactions

(Read Only). Returns kTrue if the driver supports more than one
active transaction at the same time, kFalse if only one
transaction can be active at any time.

$multipleresultsets

(Read Only). Returns kTrue if the data source supports multiple


result sets, kFalse if it does not.

$isolationoptions

(Read Only). Returns a bitmask value representing the


transaction isolation levels supported by the driver. The bit
positions correspond to the constant values listed in the Catalog
under ODBCDAM-Isolation Levels.

$isolationlevel

Returns the current transaction isolation level in use by the


session. To change the isolation level, assign one of the
constants listed in the Catalog under ODBCDAM-Isolation
Levels. The isolation level must be one the levels advertised by
$isolationoptions.
Changing the isolation level implicitly invokes a $commit().

ODBC

Session Methods
Method

Description

$getdrivers()

SessObj.$getdrivers(lResult) retrieves a list of all ODBC drivers installed on


the system. lResult is populated with the list of drivers installed and is
defined with the following character columns:
DriverName
Version
CompanyName
FileName

The alternate driver name (i.e. the descriptive name)


The version string reported by the driver
The Company name embedded within the driver file
The physical path and file name of the driver

CompanyName is only obtainable for Win32 and will return as empty for
other platforms. DriverName is obtainable directly from the driver only for
Win32. Other platforms require each driver to be loaded and called in order
to obtain the version string. Hence, there will be a commensurate delay
when calling this method.
Example:

$getdatasources()

Do sessObj.$getdrivers(iDriverList) Returns #F

SessObj.$getdatasources(lResult, kDSNMode) retrieves a list of ODBC


DSNs of type specified by kDSNMode which should be passed as either
kODBCSystemDSN or kODBCUserDSN. $getdatasources() does not
support File DSNs (see below). On return, lResult is defined with two
character columns:
DSNName The User assigned name for the data source
Driver
The alternate name of the driver associated with the data source
Example: Do sessObj.$getdatasources(iDSNList,kODBCSystemDSN)
Returns #F

$getinfo()

$getinfo(lResult, cDSNName, kDSNMode) retrieves the information


defined for the specified data source or driver as a list of keyword-value
pairs. kDSNMode should be passed as either kODBCSystemDSN,
kODBCUserDSN or kODBCDriverInfo.
$getinfo() does not support File DSNs for which standard FileOps methods
can be used to read/modify as required.
On return lResult is defined with the following character columns:
KeyWord The name of the DSN/driver attribute
Value
The value of the DSN/driver attribute
Example: Do sessObj.$getinfo(iDSNinfo,myDsn,kODBCUserDSN)
Returns #F

331

Chapter 9Server-Specific Programming


Method

Description

$setinfo()

$setinfo(cDSNName, kDSNMode, lData) writes the information


contained in lData to the specified Data source or Driver key in the
system information. lData should be defined with Keyword and
Value columns as returned by $getinfo().
If kDSNMode is kODBCDriverInfo, this has the effect of modifying
system information for the specified driver. cDSNName should
contain the descriptive name of the ODBC Driver as opposed to the
physical file name.
If kDSNMode is kODBCSystemDSN or kODBCUserDSN, this has
the effect of modifying the specified data source.
$setinfo() does not register a new data source or driver although it
will write data to the DSN as though it already exists. To properly
create a data source; use the $configdsn() method instead. To
properly register a driver, you should refer to the vendors
installation program.
Example: Do sessObj.$setinfo(myDsn,kODBCUserDSN,iDSNinfo)
Returns #F

$configdsn()

$configdsn(kDSNMode, kRequestType, cDriverName, lAttributes) allows


the specified datasource to be created, modified or removed.
kDSNMode should be either kODBCSystemDSN or kODBCUserDSN.
$configdsn() does not support configuration of File DSNs- for which an
alternative strategy is provided. kRequestType should be passed as either
kODBCAddDSN, kODBCModifyDSN or kODBCRemoveDSN.
cDriverName should correspond with the descriptive name of the driver (i.e.
not the physical file name).
lAttributes should be defined with two character columns and is used to pass
keyword-value pairs to the driver manager sufficient to perform the required
action. Usually this involves adding a single line to the list to identify the
DSN to be created/modified/removed, e.g.
KeyWord
DSN

Value
dsnname

but can also include other keywords that are allowed by the driver.
When $uselogonprompt is set to kODBCPromptNever, this prevents
$configdsn() from opening setup dialogues. The DSN is created/modified
silently using values read from the attribute list instead.
Example: Do sessObj.$configdsn(kODBCUserDSN,kODBCAddDSN,
SQL Server,lAttribList) Returns #F

332

ODBC
Method

Description

$getoption()

$getoption(kOption, cAttribute) allows the value of an ODBC configuration


attribute to be retrieved.
kOption should be passed as one of the following constants:
kODBCTrace
Requests the TRACE on/off flag
kODBCTraceLib Requests the name and path to the ODBC trace library
kODBCTraceFile Requests the name and path to the ODBC trace log
kODBCFileDSNDir Requests the default directory containing file DSNs
kODBCPerfMon Requests the Performance monitoring on/off flag
kODBCRetryWait Requests the connection pool RetryWait timeout
On return, cAttribute contains the value of the requested option as a
character string.
Example: Do sessObj.$getoption(kODBCFileDSNDir,iFileDSNDir)
Returns #F

$setoption()

$setoption(kOption, cAttribute) allows the value of an ODBC configuration


attribute to be modified. kOption should be either kODBCTrace,
kODBCTraceLib, kODBCTraceFile, kODBCFileDSNDir, kODBCPerfMon
or kODBCRetryWait. cAttribute should contain a character string
representing the new value for the specified configuration option.
Example: Do sessObj.$setoption(kODBCTraceFile,iTraceFile) Returns #F

Connecting to your Database


To connect to your database using ODBC, you need to create a session object with a
subtype of ODBCSESS. In order to log on to the database using the SessObj.$logon()
method, the hostname must contain the data source name from the ODBC control panel and
the user name and password should contain the values required by the data source. If using a
SQL Server data source that uses trusted connections, the user name and password are
omitted, for example
Do SessObj.$logon('MyDataSource', , , 'MySession') Returns #F

When the session property $usefiledsn is set to kTrue, this specifies that the hostname
parameter is to be treated as a file data source name by the driver manager.
When the session property $uselogonprompt is set to kODBCPromptComplete, this
specifies that the driver will prompt for missing logon information. Note that not all drivers
support prompting and this may result in the logon failing.

Making a DSN-less Connection


To make a connection without using an ODBC DSN, all of the information necessary to
make a connection needs to be passed as an ODBC connection string and the session
$uselogonprompt property needs to set to kODBCPromptDsnLess.
The connection string is passed to the $logon() method via the hostname parameter. The
username and password parameters are left blank.
333

Chapter 9Server-Specific Programming


ODBC connection strings consist of keyword-value pairs separated by semi-colons and are
database specific. Examples of such strings include:
For SQL Server:
Driver=SQL Server; Server=192.168.0.10; Database=accounts; Uid=fred;
Pwd=secret

For the Omnis ODBC Driver:


Driver=Omnis ODBC Driver; DataFilePath=c:\TRAVEL.DF1;
Username=myuser; Password=mypassword

For specific details on connection strings, please refer to the documentation supplied with
the RDBMS or with the ODBC driver.

Transactions
Generally, using manual transaction mode results in increased performance because the
session object does not force a commit after each statement.
If you do not have a result set pending, ODBC session objects will commit each statement if
the transaction mode is automatic. If the transaction mode is server, the session may be
committed depending on the behavior of the ODBC driver.

Dates
The session property $defaultdate allows default values to be added to date values mapped
to the server where the Omnis date value does not contain complete information, e.g. a
Short time mapped to a server date time.

Multiple cursors
To allow multiple select cursors when connecting to Microsoft SQLServer the statement
issuing the SELECT must have the $usecursor property set to kTrue before the statement is
executed. If a statement is issued when $usecursor is kFalse and this statement returns a
result set, this will prevent all other statements in the same session from returning data. The
blocking results must be completely processed or cleared before another result set can be
generated. If a commit or rollback is performed on the session, all the sessions statement
cursors will be closed and all pending results will be lost. Note that a SQLServer cursor
only allows SQL SELECT and EXECUTE procedure commands to be issued.

334

ODBC

SQL Server 2000 Data Types


The following new types were introduced with Microsoft SQLServer2000:
SQL_BIGINT
Values fetched into Omnis from BIGINT columns are converted into the Character 20 type.
This is necessary since BIGINTs are stored in 64 bits, giving them a range of 263 or
-9223372036854775808 to 9223372036854775807. The largest numeric value which can
be stored using the Integer 32 bit type is 231 or 2147483648 to 2147483647.
Omnis Character variables can be input into BIGINT columns provided that the character
length (precision) does not exceed 19.
Note: Hash variables such as #S1 cannot be bound as input variables for BIGINT columns
since their length is preset to 10,000,000.
SQL_VARIANT
Values fetched from SQL_VARIANT columns are converted into the Binary type so they
can be preserved in their raw format.
Since the data type, precision and scale are not known prior to fetching, it may be necessary
to pre-process the table before retrieving the variant data. This is done using the
SQL_VARIANT_PROPERTY() function to build a list of variant types contained in a
specified column.
Do myStatement.$execdirect(select
cast(SQL_VARIANT_PROPERTY(col3,'BaseType') as char(32)) from
mytable) returns #F

When fetching the data into Omnis, the CAST() function can then be used inside the
SELECT statement to ensure that the incoming data gets converted to the proper Omnis
types.
Do myStatement.$execdirect(select CAST(col3 as smalldatetime) from
mytable) returns #F

For this reason, tables containing SQL_VARIANTs are probably best used in tandem with
an index column, which is used to associate a cast type with each row. Since there is no
variant type in Omnis, there is no systematic way of reading a whole column of variants.
Note: text, ntext, image & timestamp types are not supported by SQL_VARIANT.
Custom Data Types
When custom data types are fetched from SQL Server their base type is abstracted from the
custom type and returned to Omnis. For example, if a custom data type is created using;
Do myStatement.$execdirect(EXEC sp_addtype birthday, datetime, 'NOT
NULL') returns #F
Do myStatement.$execdirect(create table test(col1 integer,col2
birthday)) returns #F

335

Chapter 9Server-Specific Programming


Then, a $columns() performed on the table, describes col2 as DATETIME
If a custom data type is specified when creating or altering a table, this is passed straight
through the DAM.
TABLE
The TABLE data type can be used in two ways.
The first is as a local variable in a user SQL function. Local variables are defined as type
table and can be used to temporarily store the result of a query. This usage is beyond the
scope of Omnis however.
The second is as the return value from a user-defined function. For example, the following
function defines a table as its return value. (The table must be defined in the RETURNS
section.):
CREATE FUNCTION Function1 ( @Param integer )
RETURNS @myTable TABLE
(
col1 integer, col2 char(32)
)
AS
BEGIN
INSERT @myTable
SELECT * FROM valuetest WHERE col1 > @Param
RETURN
END

Omnis can then call the function to obtain the table results, e.g.:
Do mylist.$define(col1,col2)
Do myStatement.$execdirect(select * from Function1(50)) returns #F
Do myStatement.$fetch(myList,kFetchAll)

ODBC Administration
The $getdrivers(), $getdatasources(), $getinfo(), $setinfo(), $configdsn(), $getoption() and
$setoption() session methods (documented above) allow the ODBC DAM to be used to add,
modify and remove ODBC Data Source Names (DSNs) as well as to retrieve and modify
information about ODBC drivers and general ODBC administration attributes.
The $uselogonprompt property has been modified to allow driver prompting to be forced if
required.
All of these methods return a boolean value to indicate successful operation. Errors
generated by these methods are returned as normal via the session objects
$nativeerrorcode and $nativeerrortext properties.

336

ODBC

Configuration of File DSNs


Using $getoption() to retrieve the default directory for file DSNs allows the FileOps
component to be used together with other 4GL techniques in configuring File datasources.
To create a File DSN, you should prompt for the new filename (the DSN Name) and use
FileOps to create the new file. One or more KeyWord-value pairs should also be written to
the file, e.g. DRIVER=drivername- the minimum requirement for a File DSN. To complete
the setup of the new DSN, you should follow the procedure for modifying/testing the File
DSN.
To modify or test a File DSN, use the following procedure:

Set $usefiledsn to kTrue

Set $uselogonprompt to kODBCPromptAlways

Execute $logon() with the name of the File DSN as the hostname.

Under Win32, this prompts the ODBC Administrator library to display the driver specific
logon dialogue which prompts for information necessary to make the connection. If the
DAM is successful in logging on, the Administrator library writes the additional information
back to the File DSN, hence modifying the datasource.
To remove a File DSN, you should use the FileOps component to manually delete the
specified filename.

OS X and Linux Considerations


Under Unix, the DAM locates user DSN information (odbc.ini) using the value of the
ODBCINI environment variable if is set. If ODBCINI is not set, the DAM attempts to use
the ".odbc.ini" (hidden file) in your users home directory or failing that, it defaults to
"/Library/ODBC/odbc.ini".
The DAM locates system DSN information using the value of the ODBCSYSINI
environment variable if it is set. If ODBCSYSINI is not set, the DAM attempts to locate the
system driver information using the value of ODBCINSTINI instead. If ODBCSYSINI is
set, this location is also assumed for the location of the driver information file (odbcinst.ini).
Note that if set, ODBCSYSINI should identify a folder only- not a file name.
The ODBC Driver manager used on your system must support the necessary API calls in
order to perform certain administration functions (editing and modifying DSN information,
for example). If the required API calls are missing, these functions will not be available.

337

Chapter 9Server-Specific Programming

ODBC Troubleshooting
The following points may help in resolving issues in programming applications that use
ODBC session objects.
ODBC does not support any extended ORACLE cursor operations such as positioned
update and delete.
You must specify literals in SQL statements with single quotes ('), not double quotes
(").
Some data sources may strip trailing spaces prior to sending it to the session object.
SQL Server behaves in this way.
Further troubleshooting notes, how-tos and tips can be found on the Omnis website at:
www.omnis.net/technotes

ODBC Data Type Mapping


The following table describes the data type mapping for Omnis to ODBC connections.
The Omnis to ODBC mapping will attempt to pick the best match based on the types the
driver supports in the order listed. For example, if the driver supports SQL_VARCHAR and
SQL_CHAR data up to a maximum column size of 255, but SQL_LONGVARCHAR data
up to 2 GB, an Omnis Character(1000) will map to whatever the associated server native
type is for SQL_LONGVARCHAR, e.g. TEXT.

338

ODBC

Omnis to ODBC
Omnis Data Type
CHARACTER
Character(n)
National(n)

DATE/TIME
Short date (all subtypes)

Short time

Date time (#FDT)


NUMBER
Short integer (0 to 255)
Integer 64 bit
Integer 32 bit
Sequence

Short number 0-2dp


Number floating dp, 0..14 dp

OTHER
Boolean

Picture, Binary, List, Row,


Object, Item reference

[1]

ODBC Data Type


[1]

SQL_VARCHAR(n)
SQL_CHAR(n)
[1]
SQL_LONGVARCHAR(n)
SQL_CLOB(n) (DB2 only)
[1]

SQL_DATE
SQL_TYPE_DATE
SQL_TIMESTAMP
SQL_TYPE_TIMESTAMP
SQL_TIME
SQL_TYPE_TIME
SQL_TIMESTAMP
SQL_TYPE_TIMESTAMP
SQL_TIMESTAMP
SQL_TYPE_TIMESTAMP
SQL_TINYINT (unsigned)
SQL_SMALLINT
SQL_BIGINT
SQL_CHAR(20)
SQL_INTEGER
SQL_NUMERIC(10,0)
SQL_DECIMAL(10,0)
SQL_FLOAT
SQL_DOUBLE
SQL_NUMERIC(p,s)
SQL_DECIMAL(p,s)
SQL_FLOAT
SQL_DOUBLE
SQL_BIT
SQL_TINYINT
SQL_SMALLINT
SQL_NUMERIC(1,0)
SQL_DECIMAL(1,0)
SQL_CHAR(1)
SQL_VARCHAR(1)
SQL_FLOAT
SQL_VARBINARY(blobsize)
SQL_BINARY(blobsize)
SQL_LONGVARBINARY(blobsize)
SQL_BLOB(blobsize) (DB2 only)
Where blobsize is SessObj.$blobsize

Refer to the $nationaltowchar property for use with the Unicode version of Omnis Studio

339

Chapter 9Server-Specific Programming

ODBC to Omnis
ODBC Data Type
CHARACTER
SQL_CHAR(n)
SQL_VARCHAR(n)
SQL_LONGVARCHAR(n)
SQL_WCHAR(n)
SQL_WVARCHAR(n)
SQL_WLONGVARCHAR(n)
SQL_CLOB(n)
DATE/TIME
SQL_DATE
SQL_TYPE_DATE
SQL_TIME
SQL_TYPE_TIME
SQL_TIMESTAMP
SQL_TYPE_TIMESTAMP
NUMBER
SQL_DECIMAL(p,s)
SQL_NUMERIC(p,s)
SQL_SMALLINT
SQL_TINYINT (unsigned)
SQL_TINYINT (signed)
SQL_INTEGER
SQL_BIGINT
SQL_REAL
SQL_FLOAT
SQL_DOUBLE
SQL_BIGINT
OTHER
SQL_BIT
SQL_BINARY
SQL_VARBINARY
SQL_LONGVARBINARY
SQL_BLOB
SQL_GUID
SQL_VARIANT
Custom Data Types
Table Type

340

Omnis Data Type


Character(n)

Short date 1980


Short time
Date time (#FDT)

Number (s)dp
Integer 32 bit
Short integer
Integer 32 bit
Integer 32 bit
Integer 64 bit
Number floating dp

Character 20
Boolean
Binary

Binary
N/A
N/A

JDBC

JDBC
This section contains the information you need to access a database using the JDBC object
DAM and JDBC drivers (plus their associated middleware where applicable), including
server-specific programming, data type mapping and troubleshooting. For general
information about logging on and managing your database using the SQL Browser, refer to
the earlier parts of this manual.

Minimum Requirements
To use the JDBCSESS object the client machine must have the Java Runtime Environment
v1.4 or higher installed. In addition, the JDBCSESS object will only support JDBC 2.x
certified drivers. The JDBC DAM utilises the Omnis Java Engine (OJE), so it is important
that the requirements for the OJE are also met. In particular a JVM_PATH environment
variable must be set to the path of the JVM library in order for the OJE to start the Java
Virtual Machine.

Properties and Methods


In addition to the base properties and methods documented in the SQL Programming
chapter, the ODBC DAM provides the following additional features.

Session Properties
Property
$dbmsname
$dbmsversion

$drivername

$driverversion

$logontimeout
$querytimeout

Meaning
Once a session has been established this is the type of database that
the object is connected to. This defaults after a $logoff. (Read only)
Once a session has been established this is the version of the
database software that the object is connected to. This defaults after
a $logoff. (Read only)
Prior to a session being established this should be set to the name of
the JDBC driver that the object wishes to use in order to establish a
connection. This can also be set using the $setdriver() method.
Once a session has been established this is the version of the JDBC
driver that the object is connected to. This defaults after a $logoff.
(Read only)
The timeout in seconds for a $logon call. The default is 15 seconds.
A value of 0 represents no timeout.
The timeout in seconds for a query. A value of 0 represents no
timeout, which is the default.

341

Chapter 9Server-Specific Programming

Session Methods
Property
$setdriver()

Meaning
$setdriver(drivername) sets the JDBC driver that the session
object should use to establish a connection. This is the same as
assigning a name to $drivername.

Connecting to your Database


To connect to your database, you need to create a session object with a subtype of
JDBCSESS. Unlike the other Session objects, JDBC requires a pre-logon step of specifying
the JDBC driver name to be used. This is performed using the session method $setdriver().
For example:
Do SessObj.$setdriver(sun.jdbc.odbc.JdbcOdbcDriver)

Failure to perform this step will cause the $logon() to fail. In order for the specified JDBC
driver to be successfully loaded, it must exist in the system CLASSPATH environment
variable.
To log on to the database using the SessObj.$logon() method, the hostname must contain
the database URL required by the specified driver. The user name and password should
contain the values required by the database.

Transactions
Generally, using manual transaction mode results in increased performance because the
session object does not force a commit after each statement.
If you do not have a result set pending, JDBC session objects will commit each statement if
the transaction mode is automatic. If the transaction mode is server, the session may be
committed depending on the behavior of the JDBC driver.

Dates
The session property $defaultdate allows default values to be added to date values mapped
to the server where the Omnis date value does not contain complete information, e.g. a
Short time mapped to a server date time.

Multiple cursors
To allow multiple select cursors when connecting to Microsoft SQLServer, the statement
issuing the SELECT must have the $usecursor property set to kTrue before the statement is
executed. If a statement is issued when $usecursor is kFalse and this statement returns a
result set, this will prevent all other statements in the same session from returning data. The
blocking results must be completely processed or cleared before another result set can be

342

JDBC
generated. If a commit or rollback is performed on the session, all the sessions statement
cursors will be closed and all pending results will be lost.

JDBC Data Type Mapping


The following table describes the data type mapping for Omnis to JDBC connections. The
Omnis to JDBC mapping will attempt to pick the best match based on the types the driver
supports in the order listed. For example, if the driver supports VARCHAR and CHAR data
up to a maximum column size of 255, but LONGVARCHAR data up to 2 gig, an Omnis
Character(1000) will map to whatever the associated server native type is for
LONGVARCHAR, e.g. TEXT.

343

Chapter 9Server-Specific Programming

Omnis to JDBC
Omnis Data Type
CHARACTER
Character(n)
National(n)

DATE/TIME
Short date (all subtypes)
Short time
Date time (#FDT)
NUMBER
Short integer (0 to 255)
Sequence

Integer 32 bit

Integer 64 bit
Short number 0-2dp
Number floating dp, 0..14 dp
OTHER
Boolean

Picture, Binary, List, Row,


Object, Item reference

344

JDBC Data Type


VARCHAR(n)
CHAR(n)
LONGVARCHAR(n)
CLOB(n)
DATE
TIMESTAMP
TIME
TIMESTAMP
TIMESTAMP
SMALLINT
INTEGER
NUMERIC(10,0)
DECIMAL(10,0)
FLOAT
DOUBLE
BIGINT
FLOAT
DOUBLE
BIT
SMALLINT
NUMERIC(1,0)
DECIMAL(1,0)
CHAR(1)
VARCHAR(1)
FLOAT
VARBINARY(blobsize)
BINARY(blobsize)
LONGVARBINARY(blobsize)
BLOB(blobsize)
Where blobsize is SessObj.$blobsize

JDBC

JDBC to Omnis
JDBC Data Type
CHARACTER
CHAR(n)
VARCHAR(n)
LONGVARCHAR(n)
CLOB(n)
DATE/TIME
DATE
TIME
TIMESTAMP
NUMBER
SMALLINT
INTEGER
BIGINT
DECIMAL(p,s)
NUMERIC(p,s)
REAL
FLOAT
DOUBLE
OTHER
BIT
BINARY
VARBINARY
LONGVARBINARY
BLOB

Omnis Data Type


Character(n)

Short date 1980


Short time
Date time (#FDT)
Integer 32 bit
Integer 32 bit
Integer 64 bit
Number floating dp

Boolean
Binary

345

Chapter 9Server-Specific Programming

Amazon SimpleDB DAM


The Amazon DAM (DAMAZON) allows you to access the SimpleDB from Amazon Web
Services LLC. According to Amazon, SimpleDB is a highly available, scalable, and
flexible non-relational data store that offloads the work of database administration.
Developers simply store and query data items via web services requests, and Amazon
SimpleDB does the rest. For further information about Amazon SimpleDB, please refer to
the Amazon SimpleDB website:
General information
http://aws.amazon.com/simpledb
Developers Guide
http://docs.amazonwebservices.com/AmazonSimpleDB/latest/DeveloperGuide/
This section also discusses various topics which differentiate cloud-based connectivity from
traditional RDBMSs and the impact this has on the various properties and methods.

Dependencies
The Amazon DAM has runtime dependencies on several other dynamic libraries which
must be present on your systems library search path before the DAM can be used. When a
DAMAZON session object is created, the DAM attempts to locate and resolve the symbols
it needs from each of the external libraries.
If one or more symbol references cannot be resolved, these are reported to the Omnis trace
log as warnings, $logon() is disabled and you should not attempt to call session or statement
methods, otherwise a crash may occur.
The additional files required by the Amazon DAM for each platform are as follows:
Windows
libcurl.dll (requires msvcr90.dll)
libeay32.dll (requires msvcrt.dll)
libxml2.dll (requires iconv.dll & zlib1.dll)
OS X
libcurl.dylib (where libcurl.dylib -> /usr/lib/libcurl.4.dylib, for example)
libcrypto.dylib (where libcrypto.dylib -> /usr/lib/libcrypto.0.9.7.dylib, for example)
libxml2.dylib (where libxml2.dylib -> /usr/lib/libxml2.2.dylib, for example)

346

Amazon SimpleDB DAM


Linux
libcurl.so (/usr/lib/libcurl.so)
libcrypto.so (/usr/lib/libcrypto.so)
libxml2.so (/usr/lib/libxml2.so)
If these libraries are not present on your system, the appropriate package(s) may need to be
installed or alternatively, downloaded and compiled from source. The principal libraries
shown are all available under open source licence agreements.
For developers interested in downloading and compiling client libraries from source,
information about each of the projects can be obtained from:
libcurl: http://curl.haxx.se/
libxml2: http://xmlsoft.org/
libcrypto/libeay32 : http://www.openssl.org/ (Links accurate at time of publishing)
Binary releases of these libraries may also be available to download from these and other
sources.

Logging on to SimpleDB
To connect to SimpleDB, the endpoint required is supplied via the $logon() hostname
parameter. In the case of Amazon SimpleDB, the endpoint is sdb.amazonaws.com or
sdb.eu-west-1.amazonaws.com in Europe.
Your access key id and secret are supplied via the username and password parameters, for
example:
Do SessObj.$logon(sdb.amazonaws.com, AGIBJ5LOYFITD3BR7,
H/z6t3ARzuJL26uIE07 GTS1AkK+p5) Returns #F

For other databases, the endpoint may be specified using http syntax, for example:
Do SessObj.$logon(
http://www.remoteserver.com/?,user_1,password) Returns #F

If the hostname parameter is omitted, i.e. substituted with a comma, the DAM uses
sdb.amazonaws.com by default.

347

Chapter 9Server-Specific Programming

Meta Data
SimpleDB does not provide information about tables, columns and indexes in the same way
as traditional relational databases. Instead, domains can be likened to tables, items can be
likened to rows and attributes can be likened to columns. This has an impact on the
behavior of the following meta-data methods:
$tables()

StatObj.$tables() returns a list of available domain names in the


TableOrView column of the result set. Other result columns can be ignored
as SimpleDB does not support views.

$columns()

StatObj.$columns(cDomain) returns meta data information about the


specified domain. This information is specific to SimpleDB and is returned
via the DamInfoRow column of the result set. Other result columns can be
ignored.

$indexes()

StatObj.$indexes() is not implemented since SimpleDB handles indexing


automatically.

The information returned by $columns() for a domain is summarised as follows:


Timestamp

The date and time when metadata was calculated in Epoch


(UNIX) time.

ItemCount

The number of all items in the domain.

AttributeNameCount

The number of unique attribute names in the domain.

AttributeValueCount

The number of all attribute name/value pairs in the domain.

ItemNamesSizeBytes

The total size of all item names in the domain, in bytes.

AttributesValuesSizeBytes

The total size of all attribute values, in bytes.

AttributeNamesSizeBytes

The total size of all unique attribute names, in bytes.

SimpleDB Attributes and Multi-Values


Unlike Relational databases, SimpleDB attributes support multiple values. For example:
Domain

Item

Attribute

Value

Suits

Gents Formal Suit

Colour

Navy

Suits

Gents Formal Suit

Colour

Black

Suits

Gents Formal Suit

Colour

Grey

In addition, SimpleDB effectively supports only a single data type: Character. All data
inserted into and retrieved from SimpleDB will be character data optionally encoded as
UTF-8 bytes. Once fetched into Omnis, data can be assigned to typed variables as required.
Such data will be automatically converted to the appropriate data type where possible.

348

Amazon SimpleDB DAM


Each item fetched from SimpleDB can potentially have a different number of attributes and
attribute names. This prevents the use of Omnis Schema classes with SimpleDB since these
require rigid column names and types. When dragging a schema class onto a SimpleDB
session in the Omnis SQL Browser, all that can sensibly be achieved is to create a domain
with the supplied table name.
SimpleDB does not support SQL in the traditional sense. You cannot use $prepare() &
$execute() or $execdirect() to execute INSERT, UPDATE or DELETE statements as these
are not supported. Instead, these statement methods can be used only to execute SELECT
statements conforming to the SimpleDB SELECT syntax.

Creating a Domain
To manually create a domain (analogous to a table), use the StatObj.$createdomain()
method. For example:
Do StatObj.$createdomain(Project810) Returns #F

Inserting Data
To insert items and attributes into SimpleDB, use the StatObj.$putattrib() method.
Each call to $putattrib() inserts a new attribute-value pair into the specified domain item.
(There is no need to create the item before inserting an attribute, the item is created
implicitly). Since SimpleDB supports multiple attribute values, you can assign several
different values to the same attribute if required. Duplicate values are ignored. For example:
Do StatObj.$putattrib(Project810,Materials,Tools,13mm
Wrench) Returns #F
Do StatObj.$putattrib(Project810,Materials,Tools,Quick
release clamps) Returns #F

If many attributes are to be inserted, it may be preferable to assign the domain name to the
StatObj.$domain property and the item name to the StatObj.$item property. These
parameters can subsequently be omitted in calls to $putattrib()- and any of the other
statement methods discussed below. The above example becomes:
Do
Do
Do
Do

StatObj.$domain.$assign(Project810)
StatObj.$item.$assign(Materials)
StatObj.$putattrib(, ,Tools,13mm Wrench) Returns #F
StatObj.$putattrib(, ,Tools,Quick release clamps) Returns #F

349

Chapter 9Server-Specific Programming

Deleting Data
To delete items, attributes and values from SimpleDB, use the StatObj.$delete() method.

Deleting Values
To delete a specific attribute value, the domain, item, attribute name and value should be
specified. For Example:
Do StatObj.$delete(Project810,Materials,Timber,50x50x2.4m
pse) Returns #F

Deleting Attributes
To delete an attribute including all of its values, the domain, item and attribute name only
should be specified. For example:
Do StatObj.$delete(Project810,Materials,Timber) Returns #F

Deleting Items
To delete an entire item including all its attributes and values, the domain and item name
only should be specified. For example:
Do StatObj.$delete(Project810,Materials) Returns #F

Deleting a Domain
StatObj.$delete() cannot be used to delete a domain. To do this- use
StatObj.$deletedomain(). This method should be used with caution as it will permanently
delete all items, attributes and values contained in the domain before removing the domain
itself. For example:
Do StatObj.$deletedomain(Project810) Returns #F

Replacing Data
Whereas $putattrib() is used to append new attributes and values, StatObj.$replaceattrib() is
used to replace all values for a specified attribute with the supplied single value. For
example:
Do StatObj.$replaceattrib(Suits,Gents Formal Suit,Colour,Navy
only) Returns #F

Fetching Data
The Amazon DAM uses Amazon SELECT statements to fetch multiple items. These are
issued using the statement objects $prepare(), $execute() and $execdirect() methods in a
similar way to traditional SQL SELECT statements. The general form of a SimpleDB
SELECT statement is as follows:
select output_list from domain_name [where expression]
[sort_instructions][limit limit]

350

Amazon SimpleDB DAM


The output_list can be:
* (all attributes)
itemName() (the item names only)
count(*)
An explicit list of attributes (attribute1,..., attributeN)
For further information on the SELECT statement syntax, please refer to Amazon
SimpleDB Developer Guide.
Items in the result set are returned one row-at-a-time. StatObj.$resultspending indicates
whether there is a further item each time a call to StatObj.$fetch() is made and
StatObj.$itemcount is initially set to the number of items in the response. The destination
list or row variable is automatically redefined each time $fetch() is called. For example:
Do StatObj.$execdirect(select * from Suits where stocklevel > 1)
Returns #F
Repeat
Do StatObj.$fetch(lvRow)

Until StatObj.$resultspending = kFalse

Retrieving an Item
You can retrieve all attributes for a specific item using the StatObj.$getall() method. The
result set (a single row) generated by this call is returned using $fetch(). For example:
Do StatObj.$getall(Suits,Gents Suits) Returns #F
Do StatObj.$fetch(lvRow)

Retrieving Item Names


You can retrieve the names of items contained within a domain by calling the
StatObj.$getitems() method. The result is returned as a single item containing a single
attribute. The item names will be returned either as a comma-separated list or as a single
column list- as dictated by the $attribcsv property.
A SELECT where-clause may be optionally specified if required, in which case only the
names of items which satisfy the expression will be returned. For example:
Do StatObj.$getitems( ,where Colour like Red%) Returns #F
Do StatObj.$fetch(lvItems)

Retrieving an Attribute
You can retrieve the contents of a specific attribute using the StatObj.$getattrib() method.
The result set (a single row containing a single column) generated by this call is also
returned using $fetch(). For example:
Do StatObj.$getattrib(Project810,Materials,Tools) Returns #F
Do StatObj.$fetch(lvRow)

351

Chapter 9Server-Specific Programming

Handling Multiple Values


When fetching data, each row returned to Omnis represents one item from the specified
domain. Item attributes containing multiple values are handled in one of two ways; either as
single-column lists or as comma-separated values as dictated by the StatObj.$attribcsv
property.
When $attribcsv is set to kTrue (the default), rows fetched from SimpleDB will be defined
with Character columns. Attributes (columns) with multiple values will be returned as a
string of comma-separated values.
When $attribcsv is set to kFalse, rows fetched from SimpleDB will contain single-column
lists in each column. Each single-column list will contain one row for each attribute value.

Handling Multiple Attributes


You can put, delete and replace several attribute values at once using the
StatObj.$putmany(), StatObj.$deletemany() and StatObj.$replacemany() methods. The
attribute-value pairs to be processed are supplied via a list variable defined with two
character columns. Column 1 contains the attribute names, column 2 contains the
corresponding values. For example:
Do
Do
Do
Do
Do

myList.$define(lvChar1, lvChar2)
myList.$add(Tools,Posidrive screwdriver)
myList.$add(Tools,Metal hammer)
myList.$add(Charges,1 hours labour)
StatObj.$putmany( , , myList) Returns #F

You can retrieve the values of multiple attributes using the StatObj.$getmany() method. The
attribute names to be retrieved are supplied via a single-column list, for example:
Do
Do
Do
Do
Do

myList.$define(lvChar1)
myList.$add(Tools)
myList.$add(Materials)
myList.$add(Charges)
StatObj.$getmany( , , myList) Returns #F

Each subsequent call to $fetch() returns a row containing separate attribute- either as a
comma-separated-value or as a single column list, as dictated by $attribcsv.

Handling Multiple Items


When executing queries, the StatObj.$itemcount property is set to the number of items in
the response- implying that each call to $fetch() retrieves one item.
When the response contains only attribute values, $itemcount will be set to zero.

352

Amazon SimpleDB DAM

Handling Multiple Requests


The SimpleDB DAM uses the transaction management features of the DAM interface to
allow multiple requests to be executed as a combined batch of requests. To enable multipleexecution, the SessObj.$transactionmode property should set to kSessionTranManual.
In this mode, actions such as $createdomain(), $putattrib(), $getattrib(), $replacemany() and
$execdirect() are accepted unconditionally into a queue. Nothing is sent to or received from
the database until a SessObj.$commit() is executed, at which point each request is submitted
in turn.
Unlike single request execution, every multiple request generates a response. Although
actions to put, create, replace and delete attributes will return empty responses, this enables
any errors and execution information associated with each action to be returned. For
example:
Do
Do
Do
Do
Do
Do

cSess.$begin()
cStat.$putattrib(,,'Materials','White Paint') Returns #F
cStat.$putattrib(,,'Materials',Cement 25Kg) Returns #F
cStat.$replacemany(,,lvAttribList) Returns #F
cStat.$execdirect(select * from Project810') Returns #F
cSess.$commit() Returns #F

Handling Multiple Responses


When in manual transaction mode, each call to $commit() generates one or more responses.
The number of responses available is returned via the SessObj.$responses property.
When $commit() is executed, StatObj.$itemcount and StatObj.$columncount are set to
reflect the number of items and attributes in the initial response.
Items/attributes from the response are then retrieved using one or more calls to $fetch().
When all items/attributes from the current response have been retrieved, the
StatObj.$endofresponse property is set to kTrue at which point, $itemcount and
$columncount are also set to reflect the next response.
When fetching an empty response, note that $endofresponse will effectively remain set to
kTrue. If the corresponding action generated an error, then StatObj.$nativeerrorcode and
StatObj.$nativeerrortext will be set accordingly. Otherwise, the empty response (and empty
row) can be discarded.
When all responses have been retrieved, the $resultspending property is set to kFalse,
otherwise $resultspending remains set the kTrue while there are still responses waiting.
It is safe to abandon and/or replace multiple requests before executing them by simply
calling SessObj.$begin() or changing the transaction mode back to kSessionTranAutomatic.
You can also discard pending responses in this way.
$rollback() is not supported by the SimpleDB DAM- this has no effect.

353

Chapter 9Server-Specific Programming

Machine Utilization
Amazon SimpleDB measures usage of remote resources (and hence the charge it imposes
on the end-user) in terms of box usage. Each action sent to the database incurs a box
usage- quoted as a decimal fraction of one hour. StatObj.$boxusage returns the box usage
for each action which generates a response.
The session object also has a $boxusage property which accumulates a total box usage for
the open connection. When retrieving multiple responses, the box usage for each response is
received (and added) in turn.
$boxusage may not be supported by all Simple databases in which case, the value remains
set to zero.

Read Consistency
Amazon SimpleDB supports two types of read consistency, defined as follows:
Eventually Consistent Reads
the eventual consistency option maximizes your read performance (in terms of low
latency and high throughput). However, an eventually consistent read (using Select or
GetAttributes) might not reflect the results of a recently completed write (using
PutAttributes, BatchPutAttributes, DeleteAttributes). Consistency across all copies of
data is usually reached within a second; repeating a read after a short time should return
the updated data.
Consistent Reads
in addition to eventual consistency, Amazon SimpleDB also gives you the flexibility
and control to request a consistent read if your application, or an element of your
application, requires it. A consistent read (using Select or GetAttributes with
ConsistentRead=true) returns a result that reflects all writes that received a successful
response prior to the read.
The Amazon DAM implements this functionality using the $consistentread session
property. When set to kFalse (the default setting), the eventual consistency option is used.
When set to kTrue, all $getattrib() and SELECT statement results are fetched using
consistent reads.

Conditional Puts and Deletes


The PutAttributes and DeleteAttributes API calls used by Amazon SimpleDB support
conditional put and delete operations which enable you to insert, replace or delete values for
one or more attributes of an item if the existing value of an attribute matches the value you
specify. If the value does not match or is not present, the update is rejected. Conditional
Puts/Deletes are useful for preventing lost updates when different sources write
concurrently to the same item.

354

Amazon SimpleDB DAM


The Amazon DAM implements this functionality using the $whereclause statement
property. This property affects all put, replace and delete attribute calls and accepts a SQLstyle where clause of the form:
where <name> [= <value>] [exists|does not exist]
<name> and <value> can be literal values; in which case they must be double-quoted, or
bind variables. Double quotes inside literal values should be escaped using \. For example:
Do cStat.$whereclause.$assign(where Color = Light Brown)
Do cStat.$whereclause.$assign(where Undo does not exist)
Do cStat.$whereclause.$assign(where Project \X\ = @[lvChar])

Once bound, variable values should be assigned before each call to $putattrib(), $delete(),
etc:
Do cStat.$whereclause.$assign(where Name = @[lvChar])
Calculate lvChar as Brookes
Do cStat.$putattrib(StockDB,Supplier1,Frequency,Daily)
Returns #F
Calculate lvChar as Robinson
Do cStat.$delete(StockDB,Supplier2,Frequency) Returns #F

Currently, the exists condition may only be specified if both <name> and <value> attributes
are also specified. To use does not exist, only the <name> attribute should be specified.
Subsequent calls to put, replace or delete attributes return kFalse if the condition is not met.
$whereclause is not affected by $clear(). To remove the where condition for a statement
object; assign $whereclause to an empty string.

355

Chapter 9Server-Specific Programming

Session Properties
Property

Meaning

$boxusage

Returns the cumulative total of remote machine resources consumed


since the session connected. Collects box-usages from statement
methods as well as box-usages from multiple actions (manual
transactions). Read-only.

$consistentread

If set to kTrue, all read operations (e.g. $getattrib() & $fetch()) are
executed guaranteeing that the results of recent updates are seen
immediately. If set to kFalse, the default (faster) eventual consistency
option is used.

$responses

Returns the number of responses generated by the last call to


$commit(). Applies to manual transaction mode only. Read-only.

$transactionmode

Used to implement multiple request processing. When set to


kSessionTranAutomatic each request is sent to the database
immediately. When set to kSessionTranManual, requests and queued
until a $commit() is called.

Session Methods

356

Method

Description

$begin()

Initialises/clears multiple responses in preparation for execution of a new


batch of requests. Manual transaction mode only.

$commit()

Executes a batch of statements and retrieves multiple responses from the


database. Manual transaction mode only.

Amazon SimpleDB DAM

Statement Properties
Property

Meaning

$attribcsv

If set to kTrue (the default), attributes with multiple values are returned
as comma-separated values, i.e. the fetched row will be defined with
character columns. If set to kFalse, attributes will be returned as single
column lists, i.e. the fetched row will contain a single column list in
each column.

$boxusage

For statement methods which generate a response from the database,


$boxusage returns the portion of a machine hour used to complete a
particular request. See SessObj.$boxusage. Read-only.

$domain

The current domain name. $domain will be used with various statement
methods if set. Statement methods which require a domain parameter
will assume this value if the method parameter is omitted.

$endofresponse

Returns kTrue if the last item/attribute of the current response has been
fetched in which case, $boxcount, $itemcount and $columncount are set
to reflect the next response. Read-only.

$item

The current item name. As with $domain, $item will be used with
various statement methods if set. Statement methods which require an
item name will assume this value if the method parameter is omitted.
When retrieving an item list from the database, $item is also set to the
name of the last item to be fetched.

$itemcount

Returns the number of items in the current response. Returns zero if the
response contains only attribute information. Read-only.

$resultspending

Returns kTrue while there are still items/attributes waiting to be fetched


from one or more responses. Read-only.

$whereclause

Affects all put, replace and delete attribute methods. This property
accepts a SQL-style where clause of the form:
where <name> [= <value>] [exists|does not exist]
<name> and <value> can be literal values; in which case they must be
double-quoted, or bind variables. Double quotes inside literal values
should be escaped using \

357

Chapter 9Server-Specific Programming

Statement Methods

358

Method

Description

$createdomain()

StatObj.$createdomain([cDomainName]) creates a domain with the


specified name. $createdomain() uses the value of StatObj.$domain if
the parameter is omitted in which case, $domain must be predefined.
Returns kTrue on success, kFalse otherwise.

$delete()

StatObj.$delete([cDomain],[cItem],[cAttrib],[cValue]) deletes an item,


attribute or value from the specified domain. If cDomain or cItem are
omitted, the values of StatObj.$domain and StatObj.$item are assumed
in which case, $domain and $item must be predefined.
If cAttrib and cValue are omitted, the entire item is deleted.
If cValue is omitted, the specified attribute is deleted.
Otherwise, the specified value only is deleted from the attribute.
Returns kTrue on success, kFalse otherwise.

$deletedomain()

StatObj.$deletedomain([cDomain]) deletes the specified domain and all


associated items/attributes. Warning: no further confirmation is sought
before the domain is permanently deleted. Returns kTrue on success,
kFalse otherwise.

$deletemany()

StatObj.$deletemany([cDomain],[cItem],lAttribs) deletes one or more


values from the domain item. The attribute-value pairs are supplied via
lAttribs, which should be defined with two character columns. Column
1 contains the attribute name, Column 2 contains the corresponding
value to be removed. Returns kTrue on success, kFalse otherwise.

$getall()

StatObj.$getall([cDomain],[cItem]) executes a query to return all


attributes belonging to the specified item. The result of the query is
retrieved by calling StatObj.$fetch(). Returns kTrue on success, kFalse
otherwise.

$getattrib()

StatObj.$getattrib([cDomain],[cItem],cAttrib) executes a query to


retrieve the value(s) associated with the specified attribute. The result
of the query is retrieved by calling StatObj.$fetch(). Returns kTrue on
success, kFalse otherwise.

$getitems()

StatObj.$getitems([cDomain],[cWhere]) executes a query to retrieve


the item names contained within the specified domain. If cWhere is
specified, the text is appended to the SELECT statement. The result of
the query is obtained by calling StatObj.$fetch(). Returns kTrue on
success, kFalse otherwise. $getitems() is not supported by all database
vendors.

$getmany()

StatObj.$getmany([cDomain],[cItem],lAttribs) executes a query to


retrieve one or more named attributes from the domain item. The

Amazon SimpleDB DAM


Method

Description
attribute names are supplied via lAttribs, which should be defined with
a single character column. The result of the query is retrieved by calling
StatObj.$fetch(). Returns kTrue on success, kFalse otherwise.

$putattrib()

StatObj.$putattrib([cDomain],[cItem],cAttrib,cValue) inserts a new


attribute. If cAttrib already exists, the new value is appended to the
existing value(s), otherwise a new attribute-value pair is created.
Returns kTrue on success, kFalse otherwise.

$putmany()

StatObj.$putmany([cDomain],[cItem],lAttribs) inserts one or more


values into the domain item. The attribute-value pairs are supplied via
lAttribs, which should be defined with two character columns. Column
1 contains the attribute name, Column 2 contains the corresponding
value. Returns kTrue on success, kFalse otherwise.

$replaceattrib()

StatObj.$replaceattrib([cDomain],[cItem],cAttrib,cValue) replaces all


values for the specified attribute with the specified value. Existing
values are deleted. Returns kTrue on success, kFalse otherwise.

$replacemany()

StatObj.$repalcemany([cDomain],[cItem],lAttribs) replaces one or


more attributes in the domain item. The attribute-value pairs are
supplied via lAttribs, which should be defined with two character
columns. Column 1 contains the attribute name, Column 2 contains the
new value. Existing values are deleted. Returns kTrue on success,
kFalse otherwise.

Implementation Notes
Bind Variables
Queries issued using $execute() and $execdirect() may contain bind variables- for example
in the where clause of the SELECT statement. The DAM inlines variable values into the
SQL text each time $execute() is called, placing single quotes around each value. Values
containing single quotes are escaped by adding a second single quote for each occurrence.
For example:
Calculate lVar as Katharine OHara
Do StatObj.$execdirect(select * from Customers where Name
@[lVar]) Returns #F
becomes
select * from Customers where Name = Katharine OHara

Multiple Statement Objects


The SimpleDB API does not facilitate statement isolation- only session isolation. This
means that each session object may spawn only one statement object.
An attempt to spawn a second statement object will result in an error.
359

Chapter 9Server-Specific Programming

Remote Procedures
SimpleDB does not support remote procedures, views or triggers. These are features of
traditional relational databases.

Binary Data
SimpleDB attributes support only character data of maximum length 1024 bytes and are not
suitable for storing binary data directly. A better approach (the intended approach) is that
attribute values be used to store URLs or unique identifiers for pictures, files and other
media which exist externally to the database.

360

Report Fields and Sections

Chapter 10Report
Programming
You can create many different types of report using a template or wizard, each with very
different layouts and data handling capabilities. With reports you can print out all or a
subset of your data, and collect up data from different sources and print it on a single report.
Each type of report in your application is defined as a report class. This chapter describes
report classes and report sections and their properties.
Reports can contain data fields, pictures, text, and graphics. You can also place graphs on
your reports, or base a report on an Omnis list. On the Omnis fat client, you can print
reports to a number of destinations, including the current printer, the screen, a file, a port,
the clipboard, or for the JavaScript Client you can print to a PDF file and display it in the
end users web or mobile browser.

Report Fields and Sections


You use report fields and sections to build all types of report. You can use standard data
fields that can contain data from your server or Omnis database. You can use picture fields
to display picture data. You place sections, or horizontal dividers, across your report class
that structure and position the data in the printed output. You can create subtotals, totals,
header and footer sections for most types of reports. By setting the appropriate properties in
a report class you can print labels as well. Furthermore you can add methods to a report
class and the fields and section markers on the report.
The following fields or objects are available for report classes under the Report Fields tab in
the Component Store:
Entry field
display the data from your database; you specify the variable or column name in
$dataname
Picture field
displays picture or image from your database; you specify the variable or column name
containing the picture data in $dataname
Report Positioning Bar
special type of report section that allows you to position data fields and other objects in
your report;

361

Chapter 10Report Programming


External Components
various objects and components under the External Components tab in the Component
Store

Report Wizard
The SQL report wizard lets you create a report that contains fields that map directly to a
SQL class in your library, which lets you print data on your SQL server database. Before
you can use report wizards you must create the schema, table, or file classes necessary for
SQL.
To create a new report using a wizard

Select your library in the Studio Browser

Click on the Class Wizard option, then click on the Report option

Select the report SQL Report wizard and click on the Create button

For SQL reports you need to select the Session to be associated with the new report. The
SQL report wizard creates a report based on a schema or query class; each separate field on
the new report maps to a schema column, which in turn maps to your server database
Note: there is an Omnis Report Wizard which creates a report based on an Omnis file
class which is only suitable for storage in an Omnis datafile.
When you finish in the Report Wizard the new report class is opened ready for you to
modify or print. To modify your report you need to edit its properties. You can also add
new report objects from the Component Store, and you can add methods to the report class
or the objects on the report.

Report Tools
The toolbar at the top of the report editor lets you set the page size, preview the report on
screen, and show or hide connections between the different sections of the report as shown
down the left-hand side of the report editor. In addition, you set the sort levels in your report
from this toolbar. Position your mouse over each tool to see what it does.
Some of the options in the report editor toolbar are available using the report context menu
by Right-clicking on the report background.
The Narrow Sections option displays the section markers as narrow lines which shows you
how the report will look when you print it. The Show $ident displays the ident numbers for
the fields and section markers in the report. The Field List option displays a list of fields
and section markers in the report class. You can expand the tree in the Field list to show the
fields within each report section.
362

Report Sections
The Class Methods option lets you add methods to the report class, and the Properties
option shows the properties for the class. The Page Setup option or toolbar button opens the
Page Setup dialog in which you can select the printer, and set the page size and orientation.
This dialog will vary greatly across the different operating systems.

Report Sections
Sections are horizontal markers or dividers across the report class that structure and position
the data when your report is printed. To create a complex report with headers, footers,
subtotals, and totals, such as an invoice or catalog listing, you have to place the appropriate
sections in your report class in the right order. When you enable the various sections in your
report using the Property Manager, their position and order is handled for you
automatically.
There are two sections that you must have in a report: the Record section indicates the start
of the display of records or rows of data, and the End of report section indicates the end of
the report. These sections appear automatically in every new report class.
The following section types are available.
Report heading
Page header
Subtotal heading
Subtotal heading 1 to 9
Record

Positioning

Subtotals level 1 to 9
Totals
Page footer
End of report

defines the area at the start of the report, which prints


only once; you can use this to create a report title page
defines an area at the top of each page below the top
margin, printed at the top of each new page
prints before each subtotals section; it would normally
contain column headings for your subtotal sections
each subtotal heading prints before its corresponding
subtotal level
defines the section containing the fields that print your
data; the record section expands to accommodate your
data which may extend over several pages when printed
divides a section into two or more subsections; you can
control exactly where on the page a positioning section is
printed
defines the fields that will print subtotals; you can have
up to 9 levels of subtotaling
prints at the end of the report and defines the fields that
you want to total
defines the area at the bottom of each page; printed at the
bottom of each new page of your report
defines the end of the report; must be present on every
report
363

Chapter 10Report Programming


To enable a particular report section, set the appropriate property to true in the Property
Manager. When you enable a particular report section, it is shown on your report in the
correct position. You can click on individual sections to change their properties in the
Property Manager.

Page Headers and Footers


To create a page header for your report, you must set the pageheader property of the report
to true using the Property Manager. The Page header section will appear on your report
above the Record section, or any subtotal headings if you have any.
Similarly, to create a page footer for your report, you must set the pagefooter property to
true in the Property Manager. The Page footer section will appear on your report below the
Record section, or any Subtotals and Totals sections if you have any.
Any fields or graphics you place in the header section, that is between the Page header
section and the next section marker will print at the top of each page. Likewise, any fields or
graphics you place in the footer section, that is, below the Page footer section marker, will
print at the bottom of each page. Note that the connection between the different sections is
shown in the left margin of the report editor: the current section is shown in red.
When printing to a non-paged device such as File or HTML, by default the footer section is
not printed. The Report header and first Page header sections are printed at the beginning of
the report. However it is possible to force the footer section to be printed by calling
$printsection( kFooter ) for the report instance. The default positioning for a footer for a
non-paged device is to follow on from where the last section stopped printing.
To change the height of any section, including the record, header and footer sections, you
can click on the section marker (the gray bar) and drag it into position. All the sections
below the one you move will adjust automatically.
To show you more how the report will look when you print it, you can view the sections as
narrow lines. To view sections as narrow lines, click on the Narrow sections button in the
report editor toolbar, or Right-click on the report background and select the Narrow
Sections option.

Borders and shading


You can set the border and fill properties for each section in a report. The report class and
section objects have the following new properties: $effect, $forecolor, $backcolor,
$bordercolor, $backpattern, $linestyle. In addition, sections have $topmargin, $leftmargin,
$bottommargin and $rightmargin properties to allow the sections border and fill to be inset
from the sections boundary.
Positioning sections cannot have their own border and fill properties. The border and fill of
the main section extends through all its position sections. The border and fill properties of
each section are visible in design mode.

364

Report Sections

Watermarks
You can add a watermark effect to your reports by assigning a picture to the $backpicture
property of the report. The alignment can be one of the following:
TopLeft

align the image at the top left report margin

TopCenter

align the image at the top center report margin

TopRight

align the image at the top right report margin

CenterLeft

align the image at the center left report margin

Center

align the image centrally within the report margin

CenterRight

align the image at the center right report margin

BottomLeft

align the image at the bottom left report margin

BottomCenter

align the image at the bottom center report margin

BottomRight

align the image at the bottom right report margin

Stretch

stretch the image to the report margins

Tiles

tile the image to the report margins area of the page

The horizontal and vertical DPI (dots per inch) specify the resolution at which the image is
to be printed.
When using notation, $backpicture refers to the binary representation of the image and the
formatting properties. To change the image or formatting properties you can use
$backpicture.$picture or $backpicture.$align. The full set of notation is as follows:
$backpicture.$picture

the actual image (24bit color shared).

$backpicture.$picturealign

alignment of the image within the report margins. This


can be one of the kPALxxx constants.

$backpicture.$horzdpi

the horizontal dpi (defaults to 150), disabled for


kAlignMargins and kAlignPrintable

$backpicture.$vertdpi

the vertical dpi (defaults to 150) , disabled for


kAlignMargins and kAlignPrintable.

$backpicture.$horzoffset

additional horizontal offset in cms or inches from the


alignment. Disabled for alignments of kAlignMargins
and kAlignPrintable

$backpicture.$vertoffset

additional vertical offset in cms or inches from the


alignment. Disabled for alignments of kAlignMargins
and kAlignPrintable

365

Chapter 10Report Programming

Section Positioning
When you print a report, each section follows the previous section by default, and is
positioned down the page according to the height of the previous section set in the report
class. However for some types of section, you can control where a section prints and
whether or not a new page is forced using the pagemode and startmode properties of the
section. You can use a special type of section marker called a position section to print part
of your report literally anywhere on the page. To do all these things you have to modify the
properties of the appropriate section marker.
To view the properties of a section, open your report class in design mode and click on the
appropriate section to view its properties in the Property Manager.

Page Mode
You can control whether or not Record, Subtotals, Totals, and Subtotal heading sections
start a new page when they are encountered by setting their pagemode property. You can
select one of the following options for this property.
Nopage
does not force a new page; uses the pagination in the report class (the default)
Newpage
always starts a new page before this section
Testspace
starts a new page before starting this section if there is not the specified amount of
space available on the current page
If you select the Testspace option, the pagespacing property is enabled in the Property
Manager in which you can enter the amount of space required for the section. If this amount
of space is not available on the page, a new page is started. The figure you enter in
pagespacing is shown on the section marker.
Omnis works with units that are 1/72 of an inch; therefore it may round exact numbers in
centimeters or inches to the next real unit. For example, 1cm becomes 0.99cm.

Start Mode
All sections except for Page footer and End of report let you specify the startmode, which
tells Omnis where to start the section. You can choose one of the following options.
Follow previous section
starts the section on the line following the end of the previous section (the default)
Fromtop of previous section
starts the section n inches/cms from the top of the previous section

366

Section Positioning
Fromend of previous section
starts the section n inches/cms from the end of the previous section
Fromtopmarg
starts the section n inches/cms from the top margin of the report
Frombottommarg
starts the section n inches/cms from the bottom margin of the report
When you choose one of the start modes the startspacing property is enabled in the
Property Manager, which lets you enter a measurement for the startmode. The startmode
and spacing is shown on the section marker.
Omnis ignores previous section settings if the previous section was a Page header section
or a Positioning section within a Page header section. The spacing comes before the page
start test that examines the amount of space left on a page. Omnis ignores top and bottom
margin settings for reports that are not paged.
Note that when you set up a report to print labels, you can use the Fromtop or Frombottom
options to set the spacing between your labels.
You can enter a negative value for the start spacing of a positioning section, for example
Start 1.000cms from end of previous section. This allows you to align fields with the
bottom of an extending field.

Record Spacing
The default spacing between records or rows of data on your printed report is determined by
the height of the Record section in your report class. However you can override this spacing
by setting the userecspacing property for the Record section. This property forces the
report to use the vertical spacing set in the recordspacing property of the report class.

Position Sections
A Position section is a special type of report section that you can print literally anywhere in
the report. For example, using a positioning section, you could print a footnote or a logo at
the bottom of a letter, regardless of the content or amount of data in the main report letter.
A positioning section placed over the second line of a two-line extending field with the
Follow previous section property prevents the second line from printing as a blank. You can
also follow extending fields by a positioning section with Follow previous section to
prevent them from writing over any fields below. A positioning section within a subtotal
section lets you trigger a print position change by changing a sort field value.

Section Print Height


Report sections have the property $printheight which lets you specify the printing height of
a section more accurately than using positioning sections. The printing height of a section is
367

Chapter 10Report Programming


displayed in the section bar. Setting the sections print height does not effect the positioning
of sections in the report class or on the design window. If a section area is larger than its
print height, the area below the print height is filled with gray. Any report objects that fall
entirely in the gray sections ($top of object is greater than $printheight of section) are
evaluated but not printed.
You can create label reports using a combination of the $printheight property and the
positioning mode kFitOnPage. If a section is too high to print on the current page, it will be
printed the next page. Some objects are normally moved to fit on a page at the time they are
added to the report, e.g. a single line of text. This behavior is disabled for objects in
sections that have kFitOnPage selected.
Standard Lines between sections can expect an overall vertical placement inaccuracy of +1/72nd of an inch. Hair lines can expect an overall placement inaccuracy equal to that of the
DPI of the printer, but not better than +-1/600th of an inch.

Section Calculations
Sections have the $printif property which can trigger the section to print based on a
calculation. If a section has a calculation, it is skipped if the calculation evaluates to zero,
otherwise the section is printed as normal. If a section has been given a calculation, the text
Print if calculation will appear in the section bar.
If a main section is skipped, all positioning sections belonging to the main section are also
skipped, regardless of their $printif property. Calling $printsection from a method will
ignore the $printif calculation and always print the section.

Custom Sections
A custom section is effectively a positioning section with $printif calculation of 0. This
means the section will not print unless, $printsection() is called with a reference to the
section. You can add a custom section from the Component Store.
Custom sections can be placed inside any of the main sections, but can be printed before or
after any of the other report sections, but not during. Changing the $printif calculation to
anything other than 0, will change the section into a normal positioning section, and vice
versa.

Hiding Sections in design mode


You can collapse or expand the sections in a report to simplify the visual appearance of the
report in design mode. The collapse/expand icon in the report editor lets you collapse a
section, leaving the section divider visible. The current collapse/expand state of a section
will be saved in the report class.

368

Sorting and Subtotaling


When a main section is collapsed, any positioning sections in that section are also hidden.
Positioning sections can also be collapsed or expanded individually. Collapsing of sections
is disabled when narrow sections are viewed.

Sorting and Subtotaling


To implement sorting and subtotaling for your report, you need to specify the fields on your
report to be sorted, and create subtotals sections containing those fields. Sort fields define
how Omnis subtotals the records or rows of data when printing a report. With no sort fields,
Omnis displays records in the order they are listed on your server, or if the data is from an
Omnis data file, in the order the data was inserted. When you add sort fields to your report,
the report will print subtotals when the values change in the sort fields.
To specify sort fields for your report, click on the Sort Fields button in the report editor
toolbar; the Sort fields window opens. In the Sort fields window you can specify up to nine
sort fields by entering each field or variable name in the left-hand column. Note that you
can use the Catalog to enter your field or variable names. These sort fields form a nested
sequence of sorts on the records that trigger printing of up to nine nested subtotal sections.
The sort fields for a report class are stored in the $sorts group for the class. You can modify
the contents of this group at runtime using the notation, to change the sort fields for the
report, but if you want the changes to take effect this must be done in the $construct()
method of the report before the report instance is created. If you have more than one
instance of a report class, each instance will have the sort fields specified in the class, but
you can modify the $sorts group for a particular instance if you wish to change its sort
fields.
To subtotal a field, place a copy of the field in the Subtotal section and select the
appropriate totalmode for the field. This is independent of the sort fields, which trigger the
printing of the Subtotal sections.
When you enter a field or variable name in the list of sort fields the sorting options are
enabled for that field. You can enable any of these options by clicking on the cell and
selecting true.
Each sort field has the following options.
Descending sort
sorts the field in descending (Z to A and 9 to 0) instead of the default ascending order
Upper case conversion
converts field values to upper case before sorting, so the use of mixed case in your
database does not affect subtotaling or sorting
Subtotals when field changes
tells Omnis to print subtotals using the corresponding subtotal section (1 to 9) when the
value of the field changes; that is, if sort field 4 changes, subtotal level 4 will print
369

Chapter 10Report Programming


New page when field changes
starts a new page as well as printing a subtotal when the value of the field changes
When you enable the Subtotals or New page options for a sort field, you can specify the
number of characters that must change before a subtotal is triggered or new page is printed.

Subtotal Sections
You can specify a Subtotal heading section in your report. It prints before the first Record
section and successive Record sections following each Subtotals section. The subtotal
heading can print column names and anything else you want to apply to each subtotaled
Record section.
The Subtotals section prints whenever the Record section breaks on the corresponding sort
field, with the subtotal printing before the record with the changed value. Since there are up
to nine sort fields, you can have up to nine Subtotal heading and Subtotal levels numbered 1
through 9 corresponding to the sort fields specified in the report. The higher numbered sort
fields are nested within the lower ones and hence change more often. That is, sort field 5
changes within sort field 4 which changes within sort field 3, and so on. Correspondingly,
the Subtotal heading and Subtotals sections with higher numbers print more often as the sort
fields change.
When you have multiple subtotals which print consecutively, the corresponding heading
sections print one after another, starting with the one for the last subtotal. Subtotals and
totals can be aggregations of several kinds, including sums, averages, counts, minimums, or
maximums, depending on the fields totalmode property. Omnis maintains the total for
each subtotal printing, then resets the subtotal to zero for the next section.
The Totals section prints at the end of the report. As for subtotals, you place the fields to
aggregate in this section, and Omnis accumulates the aggregate values across the entire
report. You can set the totalmode property for a field in the totals section.

370

Printing Reports

Printing Reports
Omnis provides a wide range of choices for printing your reports, including sending your
report to the printer, the screen, to a page preview, to a text or HTML file. End users can set
the report destination using the File>>Print Destination menu option. In your finished
library, you can provide a menu, popup menu, or toolbar button to print your report to the
required destination. There are a number of commands that let you set the print destination,
including Send to screen, Send to file, and Send to clipboard.
While you are creating your report class you may need to print it to try it out. You can use
one of the buttons on the report editor toolbar to print the current report class. From these
tools you can print to the current printer, a page preview window, or to the screen.

Report Destination Dialog


You can select the output destination or device for your reports from the Print Destination
dialog, available from the File>>Print Destination option on the main Omnis menu bar. This
dialog may also contain any custom devices, such as the HTML device. The devices in the
Print Destination dialog include
Printer
the current printer
Preview
reports are sent to a report preview window in Omnis
Screen
reports are sent to a report window in Omnis; the default destination
Disk
the report is sent to the file specified in the Parameters pane of the Print Destination
dialog; the file is stored in a cross-platform proprietary binary format
Clipboard
reports are sent to the clipboard in text format
Port
the report is sent to the port specified in the Parameters pane
File
the report is sent to a text file specified in the Parameters pane
RTF
the report is sent to an RTF file specified in the Parameters pane
HTML
the report is sent to an HTML file

371

Chapter 10Report Programming


PDF
the report is sent to a PDF file; for the JavaScript Client the file can be viewed in the
browser on the end users mobile device, or for the fat client the file is opened on the
end user PC assuming a PDF viewer is available
Memory and DDE/Publisher
are also available but by default are not visible in the Print Destination dialog (you can
set their $visible device preference to make them visible; see below)
To set the report destination

Select File>>Print Destination from the main Omnis menubar

Select a report destination and click OK, or double-click on a destination

Printer
The Printer option sends the report to the current printer. Under Windows, selecting the
printer as destination opens a list of installed printers, and changing to a new printer does
not affect the default printer setup as defined in the Windows Control Panel. Note that you
can change the page setup with the File>>Page Setup menu item.

Preview
The Preview option displays a full page on the screen. Text is Greeked if the screen size
is too small, dots representing the characters so that the whole page fits the available screen
area.

Screen
The Screen option is the default report destination at startup. It displays the report on the
screen without the normal page margins. You can have more than one screen/page preview
report open at a time. When you display reports on the screen, you can use the horizontal
and vertical scroll bars to view the report, and the Page up, Page down, and arrow keys as
well.
Omnis displays a screen report window as soon as it has prepared the first page of data, that
is, normally it does not wait for the report to finish. Therefore as you scroll a long report it
may take a few seconds to print each page.
Screen and Preview toolbars
Screen and Preview reports have a toolbar at the top of the window to allow end users to
print the report to the current Printer or Save the report to a file.
The Omnis root preferences $reporttoolbarscreen and $reporttoolbarpagepreview (in the
$root.$prefs devices group) allow you to select the buttons on the Screen report and
Preview toolbar for user reports.

372

Printing Reports
Copying from Screen and Preview reports
You can copy graphics in Windows metafile, bitmap or Macintosh PICT format from the
screen and page preview report window by selecting an area with the mouse and using the
Edit>>Copy menu item. You can copy text in the same way, and you can select and copy
more of the report than is displayed on screen. When you drag-and-select data in your
report, the window will scroll. The Select All option in the edit menu selects the whole
report.
The Omnis root preference $disablereportcopy (in the $root.$prefs devices group) allows
you to disable the copy via selection feature of screen reports and page previews for user
reports.

Disk
The Disk file report device sends the report output to a file on disk in a cross-platform
binary format. If you double-click on the Disk icon in the Report Destination dialog Omnis
prompts you for a disk file name.
You can print to the Disk device on one platform, reload the file in Omnis and print it on
another platform. Alternatively, you can print the output from the Disk device using the
File>>Print Report From Disk menu option, or using the Print report from disk command.

Clipboard
The Clipboard option sends the current report to the clipboard as an unpaged, text-only
report suitable for pasting as text into other applications.

Port
The Port option sends the current report to a Unix or Windows serial or parallel port, or a
Mac OS Modem or Printer port specified in the Parameters pane (Note: Serial ports are not
supported on Mac OS X). This device also uses the settings in the Page sizes pane: see the
File device.
Only one program can have a particular port open; if a port is open in Omnis and it is also,
for example, the port used by the Spooler, then the Spooler will not be able to function.
Under Mac OS, there is an option on the Parameters pane to Convert for Imagewriter. When
selected, the characters beyond ASCII 127 convert to a combination of a character,
backspace, and accent character so that the report can print accented characters and
umlauts.
If you are using a G3 or G4 Macintosh, you will not see any serial ports displayed in the
Parameters panel. This is because the latest Macintoshes do not have serial ports. However,
it is possible to connect a serial adapter to the USB port of either a G3 or G4. Once the
drivers for your serial adapter are installed correctly, Omnis Studio will automatically
recognise any new serial ports when you plug the adapter into your machine. Any new serial
ports that are discovered will be displayed in the parameters panel for you to select.

373

Chapter 10Report Programming


NOTE: Serial adapters and other USB devices which do not support the Comms Toolbox
standard will not be recognised by Omnis Studio.
You can save the settings for the Port device to a profile using the Port profile editor: see
later in this chapter for a description of the Port Profile editor. You can also setup the port
using the Set port parameters command.

File
The File print destination sends the current report to a file. If you double-click on the File
icon in the Report Destination dialog Omnis prompts you for a file name. Omnis does not
close the file at the end of the report so you can append multiple reports into a single file.
This option enables the Page sizes pane in the Report Destination dialog.
In the Page sizes pane you can specify the number of lines per page to use in reports printed
to a file or a port. Omnis stores the setting in the Omnis configuration file.
If you check the Generate paged reports check box, you can also check the Send form feed
check box, which tells Omnis to terminate pages with a form feed, or fill in the Line per
page field with a number of lines to which to pad out each page. Checking the Restrict page
width option lets you enter the number of Characters per line.

RTF
The RTF print device sends the current report to an RTF file. If you double-click on the
RTF icon in the Report Destination dialog Omnis prompts you for a file name. You can also
set the file name under the Parameters pane in the Report Destination dialog, as well as
control the how images are embedded or linked. The default behavior is to embed images in
the RTF file, but you can link the images in which case any images are stored as separate
files and linked to the RTF file; you can also ignore the images altogether.

HTML
The HTML report device is a custom device that prints a report to an HTML file on disk.
When installed and loaded it appears in the print destination dialog and behaves like any
other standard printing device. You can send any Omnis report to the HTML device and
access and change the device using the notation. If you double-click on the HTML icon in
the Report Destination dialog Omnis prompts you for a file name.
The HTML printing device uses HTML tables and standard HTML tags to position and
structure the output of the Omnis report. The default background color of the HTML file is
white. The color of the text in the original report class is retained in the HTML output file.
Where possible, the device converts any image or picture data into JPEG images, which are
written to disk and linked to the output HTML file.

Memory device
The Memory device lets you send a report to a binary variable or field, which you can hold
in memory or save in a database. At a later date you can reload the contents of the binary
variable or field and print the report to the printer or any other destination.
374

Report and Field Methods


You can access the Memory device using the notation only via the $root.$devices notation
group. By default this device is not shown in the Print Destination dialog, but you can show
it using the following method:
Do $root.$devices.//DDE/Publisher//.$visible.$assign(kTrue)

You can print the output from the Memory device using the Print report from memory
command.

DDE/Publisher Device
The DDE/Publisher lets you send a report via DDE under Windows, or to an edition under
Mac OS.
You can access the DDE/Publisher device using the notation only via the $root.$devices
notation group. By default this device is not shown in the Print Destination dialog, but you
can show it using the following method:
Do $root.$devices.Memory.$visible.$assign(kTrue)

Printing Errors
The print manager reports the following error codes and text. You can setup error handlers
to manage these errors.
1001650

Non fatal print manager error

1001670

Fatal print manager error

1001680

Print manager system error; the code is shown in the error text

1001681

Other Omnis error reported by print manager

Report and Field Methods


You can create a report class, add fields and objects to the report from the Component
Store, but to print sophisticated reports you will need to add some programming behind the
fields and sections on your report. To do this, you need to write code that uses the Omnis
print commands or methods. You can add class methods to the report itself to control
printing, and you can add field methods to each field or section marker on your report to
control things like the interval breaks and subtotals.
You can add up to 501 methods to each field or section on your report, and a further 501
methods to your report class. You enter the methods for a report class and its fields using
the method editor.
When you create a report from the Component Store it contains a $construct() and
$destruct() method by default. You can add code to these methods to control the opening
and closing of the report instance. For example, if your report uses a list you can build the
list in the $construct() method in the report. You can use the $open() method or the Prepare
375

Chapter 10Report Programming


for print command to open a report instance, you can finish a report using $endprint() or the
End print command, and you can close a report instance using the $close() method. You can
send a list of parameters to the $construct() method when you open the report instance using
the $open() method. You can send data to a report instance record by record using the Print
record command, or print an entire report using the Print report command. Alternatively,
you can send print messages to a report instance using the notation. For example, you can
send a $printrecord() message to print a record to the report instance, or send an $endprint()
message to finish the report; there is no equivalent method for the Print report command.
You can override the default handling for these messages by writing your own custom
methods with the same name. You enter these custom methods in the class methods for the
report class.
To add a method to a report class

Open your report class

Right-click on the report background to open the report context menu

Select the Class Methods option

Right-click in the method list in the method editor and add your method

To add a method to a report field or section

Open your report class

Right-click on the field or section to open its context menu

Select the Field methods option

Right-click in the method list in the method editor and add your method

The next section in this chapter describes the type of methods you can add to report classes
and objects.

376

Print Devices and the Current Device

Print Devices and the Current Device


The following properties under $root handle the group of currently installed print devices or
destinations, and the current printing device.
$devices
group of currently installed printing devices, including Printer, Preview, Screen, Disk,
Memory, Clipboard, Port, File, DDE/Publisher, and any custom devices you may have
installed. You can set a reference to a device by using
Set reference MyRef to $devices.Screen

$cdevice
the current printing device or report destination. You can change $cdevice by assigning
a device from the $devices group, for example, to specify the screen as the current
device use one of:
Calculate $cdevice as kDevScreen
Calculate $cdevice as $devices.Screen
Calculate $cdevice as $devices.$findident(kDevScreen)

Print Devices
The $root.$devices group contains the currently installed printing devices plus any custom
devices you may have installed. A device has the following properties; $canassign for these
properties is true unless specified.
$name
the name of the device; $canassign is false
$title
the string used to identify the device in the Print destination dialog
$iconid
the id of the icon for the device as displayed in the Print destination dialog, zero by
default which means the device uses the default icon
$ident
a unique numeric identifier for the device in the $devices group; $canassign is false
$visible
if true, the device is shown in the Print destination dialog
$isopen
returns true if the device is open and in use; $canassign is false
$istextbased
returns true if the device is text-based, otherwise, the device is image-based, such as
Printer, Screen, or Preview; $canassign is false
377

Chapter 10Report Programming

$cangeneratepages
this is a read only property. If it returns true, the device can generate pages and all
normal page headers and footers will be printed. If it returns false, only the report
header and first page header are printed. No footer section is printed.

$cankeepopen
returns true if the device can be kept open for long periods of time, such as the File
device; otherwise, the device should be opened prior to printing and closed
immediately after printing has finished, for example you must do this for the Printer;
$canassign is false
You can use the following methods for a device; $cando() returns true if a device supports
the method.
$open()
opens the device ready for printing or transmitting text or data. Some devices such as
the Screen or Preview can only be opened from a print job when printing a report
$close()
closes the device, if the device is open
The following example prints two reports in the same print job, and uses the $open() and
$close() methods to initialize the Printer.
Set reference theDevice to $devices.Printer
If theDevice.$isopen
;; check if printer is in use
If theDevice.$canclose()
Do theDevice.$close()
Else
Quit method kFalse
;; if device cant be closed
End if
End If
Do theDevice.$open() Returns ok
;; open the printer
If ok
;; print the reports
Set report name reportOne
Print report
Set report name reportTwo
Print report
Do theDevice.$close() Returns ok
;; close the printer
End If

$canclose()
returns true if the device can be closed. If you opened the device using $open(), this
method returns true; if you opened the device via a print job and the job is still in
progress, it returns false

378

Print Devices and the Current Device


$sendtext( cText, bNewLine, bFormFeed )
sends the text in cText to the current device; all normal character conversion takes
place. If bNewLine is true, the device advances to a new line or sends an end of line
character; if bFormFeed is true, a new page is started, or a form feed character is sent.
Data is sent in parameter order: first text, then the new line, then the form feed.
The following example sends some text to the File device.
Set reference theDevice to $devices.File
If theDevice.$sendtext.$cando()
Do $prefs.$printfile.$assign(HD:MyFile)
Do theDevice.$open() Returns ok
If ok
Do theDevice.$sendtext(Some text,kTrue) Returns ok
Do theDevice.$sendtext(More text,kTrue) Returns ok
Do theDevice.$close() Returns ok
End If
End If

$senddata( cData[,cData1] )
sends the specified data in a binary format to the device; no character conversion takes
place unless the data is of type kCharacter. If more than one parameter is specified the
data is sent in individual packets
When using the $senddata() method you must consider type conversion. The method
expects binary data, and therefore any data which is not in a binary format is converted to
binary. For example, if you pass an integer variable, the data is converted to a 4 byte
binary. In some cases, due to cross platform incompatibilities, if you want to be certain of
the order in which the data is sent, and of the values which are sent, you should use
variables of type Short integer (0 to 255), for example
Calculate myShortInt1 as 13
Calculate myShortInt2 as 10
Do myDevice.$senddata( myShortInt1, myShortInt2 )

You can send raw data to the Port or File device. The following example prints a report to a
binary variable and sends the binary data to the Port device.

379

Chapter 10Report Programming


; print a report to a binary variable
Do $cdevice.$assign($devices.Memory)
Do $prefs.$reportdataname.$assign(myBinaryField)
Set report name myReport
Print report
; now send the report to the port
Set reference theDevice to $devices.Port
If theDevice.$senddata.$cando()
Do theDevice.$open() Returns ok
If ok
Do theDevice.$sendata(myBinaryField) Returns ok
Do theDevice.$close() Returns ok
End If
End If

$flush()
flushes the device. For the File device $flush() will ensure all data is written to disk;
you can safely call $flush() for devices which do not support this method; $cando()
returns true for all devices that support $senddata() or $sendtext()

Global Printing Preferences


There are a number of Omnis preferences under $root.$prefs that handle the print devices
and their parameters. You can set these using the Property Manager or using the notation.
$reportfile
the full path and file name for the Disk device
$printfile
the full path and file name for the File device
$editionfile
the full path and file name for the DDE/Publisher device
$pages
the page or page numbers to be sent to the device; all devices support this property.
You can specify pages as a comma-separated list or range of pages separated by a
hyphen, or any combination. Prefixing a range with an e will print even pages within
the range, or with an o will print odd pages within the range. For example
1,3,7,10-15,25-20,e30-40,o30-40
$reportdataname
the name of the binary field for the Memory device

380

Global Printing Preferences


$reportfield
the name of the window field for a Preview or Screen report; if you specify this
property the report is redirected to the window field
$windowprefs
the optional title and screen coordinates for a Screen or Preview window; the syntax is
the same as the Open window command, such as My Title/50/50/400/300/STK/CEN;
the title is also used as the document name when printing to the Printer
$waitforuser
if true, method execution is halted until the user closes the Screen or Preview window
$hideuntilcomplete
if true, a Screen or Preview window remains hidden until the report is finished
The following example specifies the Screen as the current device and sets up the
preferences for the report window.
Do
Do
Do
Do

$cdevice.$assign(kDevScreen)
$prefs.$windowprefs.$assign(MyTitle/20/20/420/520/CEN)
$prefs.$waitforuser.$assign(kFalse)
$prefs.$hideuntilcomplete.$assign(kTrue)

$charsperinch
the number of characters per inch when printing to a text-based device
$linesperinch
the number of lines per inch when printing to a text-based device
$generatepages
if true, reports generate paged output when printing to text-based devices, that is, page
headers and footers are generated as normal; otherwise if false, only one report header
and page header is printed at the beginning of the report
$linesperpage
the number of lines per page when $generatepages is true
$restrictpagewidth
if true, the width of a page is restricted when printing to text-based devices
$charsperline
the number of characters per line when $restrictpagewidth is true
$sendformfeed
if true, form feeds are sent to text-based devices after each page
$appendfile
if true, data is appended to the current print file specified in $printfile, otherwise if
false, the file is overwritten when printing to the File device; note if the device is
already open prior to printing a report, the file is appended to regardless

381

Chapter 10Report Programming


$istext
if true, forces a non-text device to behave like a text-based device using the same
preferences as text-based devices
$portname
the name of the port when printing to the Port device (Not supported on OS X)
$portspeed
the port speed setting when printing to the Port device (Not supported on OS X)
$porthandshake
the handshake when printing to the Port device; this can be kPortNoHandshake,
kPortXonXoff, or kPortHardware (Not supported on OS X)
$portparity
the parity checking when printing to the Port device; this can be kPortNoParity,
kPortOddParity, or kPortEvenParity (Not supported on OS X)
$portdatabits
the number of databits when printing to the Port device; this can be kPort7DataBits, or
kPort8DataBits (Not supported on OS X)
$portstopbits
the number of stop bits to be used when printing to the Port device. This can be
kPort1StopBit or kPort2StopBits (Not Supported on OS X)
The following example sets up the preferences for the Port device.
Do $prefs.$portspeed.$assign(9600)
Do $prefs.$porthandshake.$assign(kPortNoParity)
Do $prefs.$portdatabits.$assign(kPort8DataBits)
Do $prefs.$portstopbits.$assign(kPort1StopBit)
Do $prefs.$porthandshake.$assign(kPortXonXoff)
Do $prefs.$charsperinch.$assign(10)
Do $prefs.$linesperinch.$assign(6)
; Note $charsperinch and $linesperinch are used for
; all text-based devices

There is also a group of Page setup properties under $root.$prefs giving access to the global
page settings. These are
$orientation
the page orientation; this can be kOrientDefault, kOrientPortrait, or kOrientLandscape
$paper
the paper type, a constant; one of 50 or so paper sizes or types including US Letter,
European A sizes, envelope sizes, custom sizes, and so on
$paperlength
the length of the paper in cms or inches depending on the $usecms preference
382

Report Instances
$paperwidth
the width of the paper in cms or inches depending on the $usecms preference
$scale
the scaling factor in percent
$copies
the number of copies
The Omnis root method $getprinterlist() allows you to get a list of printers available to the
current user. For example, the following method will return a list of printers:
; define local vars printer (Char), mylist (List)
Do mylist.$define(printer)
Do $root.$getprinterlist(mylist)

The current line of the list indicates the current printer.

Report Instances
Report instances have the following methods.
$printrecord()
prints the Record section; same as the Print record command
$printtotals(section)
triggers a subtotal or totals section; section is the highest level subtotal to be printed, a
constant, such as kSubtotal5 or kTotals
$printsection(section)
prints a report section; section is a constant, kRecord, kTotals, and so on, or a reference
to a field on the report instance
$accumulate(section)
accumulates the subtotals and totals section, and is sent during the printing of a record
section
$checkbreak()
checks if a subtotal break is required, returns a constant: kSubtotal1 to kSubtotal9 or
kNone if subtotal break is not required
$skipsection()
skips the current section; if you call this during $print() for a field, no further fields will
be printed for that section
$startpage(pagenumber)
starts a new page; adds the page header section to the page, and for the first page also
adds the report header section

383

Chapter 10Report Programming


$endpage(pagenumber)
ends a page and adds the footer section to the page; without parameter ends all pages
which have been started
$ejectpage(pagenumber)
ejects a page; without parameter ejects all pages which have been ended and not
ejected; this method ejects pages which have an active section intercepting their
boundary when the section has finished printing
$endprint()
finishes the report; prints the final subtotals and totals sections and ejects all the
remaining pages
$openjobsetup()
opens the job setup dialog. You can call this method immediately after $open() for a
report; if it returns kFalse as the result, the user has selected Cancel, and you should
close the report instance. You cannot call $openjobsetup() during $construct() since a
print job is not created until $construct() finishes.
$cdevice
reference to the printing device for the instance; if you wish to change the device, you
must do so before returning from $construct() of the report instance, and before you
start printing the first record. For example, execute the following at the start of
$construct() to specify the page Preview device for the current instance
Do $cinst.$cdevice.$assign($devices.Preview)

The device preferences are listed under the global printing preferences. Report instances
have their own printing preferences which are local to the instance. They take their initial
values from the global printing preferences. You can only assign values to these properties
in $construct(), and before you start printing the first record.
The $firstpage property always returns 1, and $canassign() is false. The $lastpage property
returns the last page. You cannot set $lastpage in the report instance to reduce the number
of pages generated, that is, once pages have been generated they cannot be removed from a
print job.
Note that the $pageheight property of a report instance returns the height of the printable
area excluding the margins, headers, and footer areas of the report.

384

Report Instances
The following method generates subtotal breaks every fifth record. The $reccount property
is incremented and the subtotals accumulated manually.
Do $reports.Report2.$open('*') Returns Myreport
For lineno from 1 to Mylist.$linecount step 1
Do Mylist.[lineno].$loadcols()
Calculate Myreport.$reccount as Myreport.$reccount+1
Do Myreport.$printsection(kRecord)
Do Myreport.$accumulate()
If mod(lineno,5)=0
Do Myreport.$printtotals(kSubtotal1)
End If
End For
Do myreport.$endprint()

Page Setup Report instance properties


You can change the page setup information of a report instance without effecting the global
settings. The properties which can be set are;
$pagesetupdata
this can only be calculated prior to printing the first record; the best time is during
$construct. When a print job has started, $canassign returns kFalse.
$orientation, $paper, $paperlength, $paperwidth, $scale, and $copies
any of these properties can be changed at any time during a print job, and will effect the
next page to be generated. When $startpage for a page has been called, changing these
properties will take effect from the next page onwards. A good time to make changes
for the next page is during a $endpage for the current page, but it can be done from
anywhere prior to the $startpage call for a page to be effected
$loadpagesetup
When true, the page setup information stored with the report is automatically loaded
and used when the report is printed. This will not affect the global page setup
information. The page setup information is applied to the page setup information of the
report instance prior to calling the $construct method or opening the job setup dialog. It
is also possible to load the page setup data from the $construct method of the report
instance by assigning $loadpagesetup ( $cinst.$loadpagesetup.$assign(kTrue) ).
Assigning kFalse has no effect., For new reports, this property will be set to kTrue by
default. For existing reports, this property will be false.
Once a print job is complete and $endprint has been called, $canassign returns kFalse for all
these properties.

385

Chapter 10Report Programming

Printing a report from a list


The following method prints a report from a list and uses a For loop to print the report
record by record.
Do $reports.Report1.$open('*') Returns Myreport
For lineno from 1 to Mylist.$linecount step 1
Do Mylist.[lineno].$loadcols()
Do Myreport.$printrecord()
End For
Do Myreport.$endprint()

Note that you should not use hash variables to define the columns in list if it is going to be
used as the basis of a report.

Report Field and Section Methods


Report fields and sections contain a $print() method that controls that particular field or
section when it is printed. Every time a field or section is encountered during printing its
$print() method is called, so for fields in the report Record section $print() is called for
every row of data. You must end your own custom $print() methods with a Do default
command to carry out the default processing for that line after your code has executed.
For example, the following $print() method for a report field prints the field in bold if its
value is greater that 1000.
If parm_value>1000
Do $crecipient.$fontstyle.$assign(kBold)
Else
Do $crecipient.$fontstyle.$assign(kPlain)
End If
Do default

386

Report Object Positioning

Report Object Positioning


When a report field prints, its position and data are passed to its $print() method; when a
report section prints its position only is passed. You can set up parameter variables of type
Field reference in the $print() method for a report section or field to receive its position and
data. You can manipulate the position variable using the report object positioning notation.
If you change the position of a section all objects in that section are affected together with
all subsequent sections in the report. Making changes to the position of an object does not
affect other objects.
A report position variable has the following properties.
$inst
the report instance to which the position belongs
$posmode
the mode of the report position, which is one of the following constants; assigning
$posmode does not change the physical position of the object, but it does change its
coordinates to the new coordinate system.
kPosGlobal
kPosPaper
kPosPrintable
kPosLocal

kPosHeader

kPosFooter
kPosSection

the position is global to the print job, relative to the top-left of the local
area of the first page
the position is relative to the top-left of the paper edge of the page
specified by $posvertpage and $poshorzpage
the position is relative to the top-left of the printable area of the page
specified by $posvertpage and $poshorzpage
the position is relative to the top-left of the local area (excluding the
header and footer sections, and the margins) of the page specified by
$posvertpage and $poshorzpage
the position is relative to the top-left of the header area (union of report
and page header sections) of the page specified by $posvertpage and
$poshorzpage
the position is relative to the top-left of the footer area of the page
specified by $posvertpage and $poshorzpage
the position is relative to the top-left of the section specified by
$possectident

387

Chapter 10Report Programming


In addition, you can set $posmode to one of the following values to return the coordinates
of an area on the page specified by $posvertpage and $poshorzpage.
kBndsGlobal
kBndsPaper
kBndsPrintable

kBndsLocal

kBndsHeader

kBndsFooter

returns kPosGlobal coordinates. The top, left, width, and height are
calculated to global coordinates of the local area of the page
returns kPosPaper coordinates. The top and left are zero, and the height
and width are calculated to the height and width of the paper of the page
returns kPosPrintable coordinates. The top and left are zero, and the
height and width are calculated to the height and width of the printable
area of the page
returns kPosLocal coordinates. The top and left are zero, and the height
and width are calculated to the height and width of the local area of the
page
returns kPosHeader coordinates. The top and left are zero, and the
height and width are calculated to the height and width of the header
area of the page
returns kPosFooter coordinates. The top and left are zero, and the height
and width are calculated to the height and width of the footer area of the
page

$possectident
the $ident of the section when $posmode is kPosSection
$posvertpage
the vertical page number when $posmode is not kPosGlobal or kPosSection
$poshorzpage
the horizontal page number when $posmode is not kPosGlobal or kPosSection. This
will usually be set to 1. Horizontal page numbers apply when horizontal pages are
enabled
$top
the top of the position in cms or inches local to its $posmode
$left
the left of the position in cms or inches local to its $posmode
$height
the height of the position in cms or inches
$width
the width of the position in cms or inches
Measurements are in either cms or inches depending on the setting of the usecms Omnis
preference which you can change in the Property Manager using the
Tools>>Options/Preferences menu option.

388

Report Object Positioning

Page layout
To understand the positioning notation it helps to look at the layout of the report on paper or
screen. The area available for printing is limited to the printable area on the paper as
determined by the printer or device. Within this space Omnis reports print to the header,
footer, and local or global areas, that is, the space remaining after subtracting the header,
footer, and margins specified in the class. Note that Omnis subtracts the margins specified
in the class from the paper edge, rather than the boundary of the printable area.
Header

Local or
Global area

Margins

Footer

The position of a report object, either a section or report field, is relative to the local area on
the current page, or the global area for the entire report.

389

Chapter 10Report Programming

Object

Local coordinates are relative to the local


area on the current page

Object

Global coordinates are relative to the global


area for the entire report

The following example method produces a report with multiple columns by configuring
itself according to the current paper size and orientation. The report class contains various
390

Report Object Positioning


instance variables including iCurColumn, iMaxColumns, iLeftAdjust to handle columns and
a global left adjustment. The data is taken from a list, but your data can be from any source.
The Record section contains one field that gets its data from the list. Note the code for this
method does the positioning and the Do default command prints the section.
; $print() method for Record section in a column report
; Declare Parameter var pThePos of type Field reference
; and Local var posBnds of Row type
; pThePos is in global coordinates and does not contain the page
; number, so make a copy and convert it to page-based coordinates
Calculate posBnds as pThePos
Calculate posBnds.$posmode as kPosLocal
; Fetch the global boundaries for the page; we can do this now since
; setting $posmode to kPosLocal set $poshorzpage and $posvertpage
Calculate posBnds.$posmode as kBndsGlobal
; Check if the bottom of the section will fit on the page
If (pThePos.$top+pThePos.$height)>(posBnds.$top+posBnds.$height)
; if it doesn't fit is there room for a new col on current page
If (iCurColumn<iMaxColumns)
Calculate iCurColumn as iCurColumn+1
Else
; put the section at the top of the next page for column one
Do posBnds.$offset(0,posBnds.$height)
Calculate iCurColumn as 1
End If
; now calculate the sections top position based on posBnds.$top
Calculate pThePos.$top as posBnds.$top
; calculate the sections left pos based on current column number
Calculate pThePos.$left as
(iCurColumn-1)*$cinst.$labelwidth+iLeftAdjust
Else If not(pThePos.$left)
Calculate pThePos.$left as iLeftAdjust
End If
Do default
;; this prints the Record section

You can use the $offset(x,y) method to move the object horizontally by x units (unless
$horzpages is enabled) and vertically by y units. The units are defined by $prefs.$UseCMS
and maybe either positive or negative.

391

Chapter 10Report Programming

Report Inheritance
When a report is based on a report superclass several items are inherited including report
header and footer sections (e.g. page header, subtototals, footer, etc), the objects within
these sections, as well as the sort fields in the report superclass. The objects within the
record section of the report superclass are not inherited. You can, therefore, create a report
template containing your company identity and base all other reports on the template to
ensure a uniform design and layout is maintained across all your reports.
Inherited sections cannot be manipulated in any way. You cannot resize an inherited section
by moving the section object immediately below the inherited section, or change the
properties of the section or its objects. When a section is inherited, the height of the section
is determined from the superclass, and all other sections below are moved up or down
accordingly.
For inherited sections, the text of the section bar and the text of the section connection lines
are shown in blue. The background is shown in gray to indicate that this section cannot be
manipulated.

Inheriting Sections
Modifying a Superclass
When modifying the section of a superclass, e.g. adding, removing or changing objects
within a section, these changes will be reflected in any report class which inherits the
section.
Removing an entire section from a superclass will also affect all subclasses. However,
adding a new section to a superclass will not affect any of its subclasses. To inherit the new
section, subclasses need to be modified to inherit this new section.
Any changes made to sort fields will be reflected in all subclasses.

Inheriting/Overload a section
To inherit or overload a section, right click on the section in the Property Manager. A
context menu opens allowing you to inherit or overload the property. You cannot
manipulate inherited sections, or inherited section objects, or to add more objects to an
inherited section.

Subtotal Sections and Sort Fields


A subclass inheriting a subtotal section will also inherit the sort field from the super class,
unless the subclass has already specified a sort field for the subtotal section in question. Sort
fields can be overloaded or inherited via the context menu of the sort field. The properties
of an inherited sort field cannot be changed. If you want to change the properties of an
inherited sort field you must first overload the sort field.

392

Report Fonts
When overloading a sort field, the properties of the sort field originally inherited are
maintained. If a sort field is inherited which has not been specified by its super class, the
name will be displayed as #???.

Positioning Sections
If an inherited section contains positioning sections, these are also inherited. It is not
possible to add additional positioning sections to an inherited section. It is not possible to
inherit position sections without inheriting their main section.

Notation
You can inherit or overload sections using notation. To do this you assign $isinherited of
the section notation. For example:
Do $clib.$reports.myreport.$pageheader.$isinherited.$assign(kTrue)

To inherit sort fields using notation:


Do $clib.$reports.myreport.$sorts.1.$isinherited.$assign(kTrue)

The objects of inherited sections are not part of the subclass and as such will not appear in
the list of objects of the report class, but will appear in the list of objects of a report
instance.
The following section properties can be inherited: $reportheader, $pageheader,
$subtotalhead, $subtotalhead1 to 9, $subtotal9 to 1, $pagefooter, $totals.

Report Fonts
If you are developing an application for a cross platform environment, you may want to set
up the system font tables to allow the fonts used in your application to map correctly across
the different platforms. There is a system font table for report classes and window classes
for each platform supported in Omnis.
The fonts in the report font table will appear in the $font property for report objects. So
even if you are developing an application for a single platform, you may still want to edit
the report font table to add fonts to those already available for report objects.
#WIRFONTS
#MARFONTS
#UXRFONTS
#MXRFONTS

Report font table for Windows OS


Report font table for Mac OS 9
Report font table for Unix
Report font table for Mac OS X

393

Chapter 10Report Programming


To view the report fonts system table

Use the Browser Options dialog (press F7/Cmnd-7 while the Browser is on top) to
make sure the system tables are visible in the Studio Browser

Double-click on the System Tables folder

Double-click on #WIRFONTS or the report font table for your platform

The #WIRFONTS system table contains a list of fonts that are available in Omnis by
default. Each row in the font list displays the corresponding font for each platform
supported in Omnis. To change the font mapping, replace the name of a font either by
typing its name or selecting it from the list of fonts. To add a font, click in the next available
line in the font list and add the name of the font. Add a font name for each platform.
The font table editor loads or creates a font table for each platform (corresponding to each
column in the editor) and allows you to edit them all simultaneously. Therefore when you
edit the report font table for the first time, and click OK to finish editing it, a new system
table is added to your library for each platform supported in Omnis, other than your current
platform.

Report Text Labels


You can use the standard built-in Text and Label objects in your report classes to label
report fields and so on. In addition, you can use the String Label object which allows you
provide multi-language labels on your reports: for information about the use of String
Labels and String tables, see the Localization chapter.
The Wrapping List and Data Grid report fields support the use of styled text, provided their
$::styledtext property is enabled. You can insert styling characters or text escapes into
text objects and other fields in Omnis reports using the style() function: see the Window
Programming chapter for information about using the style() function.

394

Port Profiles

Port Profiles
A port profile is a named collection of information sufficient to completely describe the
operating system configuration of a port. Under Windows, the port profile information
corresponds to the information required to set the fields in a DCB for a serial port (under
Win16 the DCB is different to Win32). There is no port profile for a parallel port, since it
requires no operating system configuration information.
Under Mac OS, the port profile information corresponds to the information required to
make the SerReset and SerHShake API calls. (Note: Port profiles are not currently
supported on OS X)
The information required to completely configure a port therefore comprises:
1. The port profile (not required for parallel ports)
2. Characters per inch.
3. Lines per inch.

Port Profile Management


Each port profile is stored in a file. The Ports folder in the Omnis tree contains the port
profiles. The port profile file contains:
An indicator of the platform to which the profile corresponds - Win16, Win32 or Mac.
This allows for runtime checking.
The name of the profile, to be used in the report destination dialog, and as an argument
to the Set port parameters command. Note that profile names are not case sensitive.
The profile data.
Note that this means that each profile file only contains the data for a single platform.
You can create and edit profiles using the Port Profile Editor. The profile editor must run on
the platform for which the profiles are to be created. For Win32 and PowerMac
development versions, the port profile editor is on the Add-ons submenu in the Tools menu.
If you wish to edit port profiles using a runtime version, there is a folder in the root of the
Studio CD, called RTTools, containing the editor library, which you copy to your hard disk,
and open to run the editor.

Port Profiles at Runtime


Report Destination Dialog
When the report destination is set to Port, the parameters tab of the dialog displays the port
configuration information. There is a dropdown list on this tab, which contains a list of
profile names, and one additional entry, Use options below. When this is selected, you can
395

Chapter 10Report Programming


specify the port parameters in the dialog. When a profile is selected, Omnis configures the
port using the information in the profile. Note that the dropdown list and configuration
fields on this tab are disabled if you select a parallel port.

Set port parameters command


You can use a port profile name in place of the port parameter list:
Set port parameters {Profile name}

When this command executes, it first checks the entire parameter string against the list of
profiles. If it matches an entry in the list, the command uses the profile to configure the port;
otherwise, the command treats the parameter string as a parameter list.

Notation
The relevant $port notation such as $portparity is unassignable when a port profile is
selected. The $portprofile property is the port profile for the current port on the Mac, or just
the single port profile under Windows.

Printer Escapes
When sending to printer, escape characters are not interpreted correctly, because the printer
driver attempts to draw them as data. You must send reports containing printer escapes to
port to ensure escape sequences are interpreted correctly.
The Omnis root preference $exportencoding ($root.$prefs) determines how the data is
converted before Omnis sends it to the port. Set this to kUniTypeAnsiLatin1 for printer
escapes to be interpreted correctly.
The escapes generated by the style() function cannot be mixed (in a report field's data) with
escapes specific to a printer.

396

Labels

Labels
To print labels in Omnis you need to create a report class and set up its properties for label
printing. You can create the report class using the standard SQL or Omnis report wizards, or
you can create an entirely New Report and add the fields yourself. This section uses the
Omnis Report wizard as the basis for a Customer address label, but the process is the same
for any label report.
To create the basis of your label report

Create a new report class using the Omnis Report wizard and include the fields you
want in your label
Open the report class to modify it
Delete the header section and any labels the report wizard places on the report class,
but leave the data fields; your report class should look something like the following

To change this report class into a label report you need to change some of its properties, set
the properties of the Record section to position your labels on the printed page, and as a
further enhancement you can set the properties of some of the fields on the report to exclude
empty lines. Note that all measurements use the current units set in the usecms Omnis
preference.
To set the label properties of a report class

Click on the background of your report class to view its properties

Set the islabel property to kTrue

Set the labelcount property to the number of labels across the page; for example, for
standard 3 x 8 laser labels you set labelcount to 3
Specify the width of a single label in the labelwidth property; if there are spaces
between your labels, include the space in the label width, that is, the labelwidth is the
distance between one record and next across the sheet of labels
If you want to print more than one label for each row or record of data set the
repeatfactor property, otherwise leave it set to 1 for a single copy of each label

397

Chapter 10Report Programming


To specify the distance between each row of labels down the page, you change the
properties of the Record section in your report class.

Click on the Record section to view its properties


Set the startmode property to kFromTop, and in the startspacing property enter the
distance between the top of one row of labels and the next going down the label sheet

Excluding Empty Lines


When you print your labels some of the fields may be empty and a blank line is printed.
However you can stop a field from printing and move up all subsequent lines by setting the
nolineifempty property for the field. For example, if your label includes two lines for the
address you can set the nolineifempty property to kTrue for the second address field. In this
case if the second address line is empty for a particular record, the line is not printed and
subsequent fields move up one line. If any address field on your label is likely to be empty
you ought to set its nolineifmpty property.

Using a Calculated Field


Rather than putting two separate fields on your label report for the Firstname and Lastname
data, you can use a single calculated field and the con() function.
To create a calculated field

Create a field on your report and view its properties

Leave the dataname property empty, and set the calculated property to kTrue

Enter the calculation in the text property, something like the following
con(CU_FNAME, ,CU_LNAME)

;; note space char is in quotes

The con() function concatenates the current values in the CU_FNAME and CU_LNAME
fields and separates them with a single space character.
Using all the features described in this section, your label report should look something like
the following when printed to the screen.

HTML Report Device


The Omnis Studio Print Manager API has been made public, allowing you to create your
own custom printing devices as external components and place them in the XCOMP folder.
You can show your own custom printing devices in the Print Destination dialog, and use the
printing preferences and notation to control your own devices. The HTML printing device
is an external component and shows what you can do with custom devices. You can use the
HTML report device in exactly the same way as the standard report destinations; there is no
difference between internal and external output devices.
398

HTML Report Device


When the HTML external component is loaded in Omnis, it registers an external output
device with the Omnis Studio Print Manager and shows the HTML icon in the Report
Destination dialog. To print to the HTML output device you can set it up via the Report
Destination dialog, or access it via the notation using the print device methods.
You can specify the HTML device using the notation as follows.
Calculate $cdevice as kDevHtml
Calculate $cdevice as $devices.Html

You can also set an item reference to the HTML device:


Set reference myDevice to $devices.Html

The constant kDevHtml is supplied by the HTML component at registration together with
some other constants.

Setting the HTML Device Parameters


The HTML output device has several parameters which affect the overall appearance of the
HTML document generated by the device. You can change some of these parameters in the
Report Destination dialog and the notation, while some can be manipulated by the notation
only.
The HTML device parameters are represented by constants which you can use in the
notation. Some of them correspond to parameters in the Report Destination dialog.
Constant

Description

kDevHtmlFileName

the pathname of the destination HTML file

kDevHtmlFont1

largest point size which maps to HTML font size 1

kDevHtmlFont2

largest point size which maps to HTML font size 2

kDevHtmlFont3

largest point size which maps to HTML font size 3

kDevHtmlFont4

largest point size which maps to HTML font size 4

kDevHtmlFont5

largest point size which maps to HTML font size 5

kDevHtmlFont6

largest point size which maps to HTML font size 6

kDevHtmlFont7

largest point size which maps to HTML font size 7

kDevHtmlImageBorder

whether JPEG images have a single pixel border

kDevHtmlUseRects

whether background rectangles are to be used to determine the


background color of the HTML table cell which intersects the
background rectangle

kDevHtmlBackcolor

background color of the HTML document

kDevHtmlTextcolor

default text color; any black text received from the print manager
will be changed to this color

kDevHtmlLinkcolor

color for HTML text or pictures which are HTML links

kDevHtmlVLinkColor

color for links which have been visited

399

Chapter 10Report Programming


Constant

Description

kDevHtmlALinkColor

color for links which are currently active

kDevHtmlTemplate

full path and file name of a template HTML file; it must already
contain the basic framework for an HTML file, that is
<HTML>
<BODY bgcolor= etc>
</BODY>
</HTML>

kDevHtmlTemplateChars

the place holder contained within the template file which marks
the point at which the report output will be inserted into the
template, that is, $$$$ the template file must contain this text,
that is
<HTML>
<BODY bgcolor= etc>
<p>$$$$</p>
</BODY>
</HTML>

kDevHtmlScaleFont

an additional single font scale factor; the following constants are


available
kDevHtmScaleFontNone: no scaling
kDevHtmScaleFontVSmall: reduce HTML size by 2
kDevHtmScaleFontSmall: reduce HTML size by 1
kDevHtmScaleFontLarge: increase HTML size by 1
kDevHtmScaleFontVLarge: increase HTML size by 2

You can get and set the value of the device parameters using the following methods.
$getparam(param constant)
returns the value of the specified parameter
$setparam(param constant, value [,param constant, value, ] )
sets the value(s) of the specified parameter(s)
For example
Do $devices.Html.$setparam(KDevHtmlFont1,6,KDevHtmlFont2,8)
Do $devices.Html.$getparam(kDevHtmlFileName) Returns MyPath

The value of all device parameters is stored in the Omnis configuration file.

Sending Text or Data


It is possible to send text or data to some internal and external devices. The HTML device
supports both. You can use the methods $sendtext() and $senddata() to send text and data,
respectively.
When sending text, the HTML output device surrounds the given text with the correct
HTML syntax, that is, it places begin paragraph and end paragraph statements around the
text. You can send text with more than one call to $sendtext(), but still have the text appear
400

HTML Report Device


in one paragraph. To do this, specify kFalse for the line feed parameter of the $sendtext()
method. The device buffers the text separately, before adding a single paragraph to the
document when you call $sendtext() with the line feed parameter set to kTrue.
When sending data, the device writes the data directly to the current position in the HTML
file without any modification.
You can send text or data between reports, but not during printing, that is, while a report is
being printed calls to $sendtext() and $senddata() are ignored.
The following method uses $senddata() to send data to an HTML file.
Set reference myDevice to $devices.Html
Calculate $cdevice as myDevice
Do myDevice.$setparam(kDevHtmlFileName,C:\Omnis\REPORT.HTM)
Do myDevice.$open() Returns ok
If ok
Do myDevice.$senddata(myData1)
Set report name Report1
Print report
Do myDevice.$senddata(myData2)
Set report name Report2
Print report
Do myDevice.$senddata(myData3)
Do myDevice.$close()
End If

HTML Report Objects


HTML report objects are special objects that you can use to insert objects, such as other
HTML documents, pictures, DLLs, or web site addresses, into your HTML reports. The
HTML report objects are part of the HTML printing device and, when the report editor is
the top window, they appear in the Component Store under the External Components
button.
The HTML report objects have an $address property which you can set to the address or
location of an HTML document, picture, DLL, or web site, for example,
results/result1.htm or http://www.rainingdata.com/. The text can contain square bracket
calculations, such as www.[lvWebName].
If the HTML objects are printed to any other device other than the HTML device, they
behave like their equivalent Omnis field types, a standard picture or text field.

401

Chapter 11Unicode

Chapter 11Unicode
Omnis Studio fully supports Unicode, which means you can expand the market for your
Omnis applications by supporting the majority of world languages and the display of special
characters, including scientific and mathematical symbols.
In previous versions of Omnis Studio, we provided a Unicode and non-Unicode version of
the development kit, but Omnis Studio 5 is Unicode compatible by default. The Unicode
version of Omnis Studio is available for Windows, Mac OS X, and Linux, and will allow
you to localize your applications and deploy them to virtually any market, anywhere in the
world.
You should also refer to the Localization chapter in this manual for information about
localizing and deploying your applications for non-English speaking markets.

What is Unicode?
Unicode provides a mechanism for representing characters or symbols used in many of the
languages in the world, as well as scientific and technical environments. The Unicode
standard is maintained by the Unicode Consortium (www.unicode.org) who set the
standards for Unicode and promote its worldwide use. They define Unicode as: a
character coding system designed to support the worldwide interchange, processing, and
display of the written texts of the diverse languages and technical disciplines of the modern
world. In the context of client-server and multi-tier computing, Unicode allows the
seamless exchange and processing of character data across different platforms, software
products and programming environments.
The Unicode consortium provides information and resources concerning Unicode, including
the standard definition and maintenance, character code tables, a locale identifier repository,
and lists of Unicode enabled products. The last major version update of Unicode was
version 5.1 which is capable of representing over 100,000 different characters, used in
many different languages throughout the world. Many operating systems and software
products have adopted Unicode, which is now universally accepted as the standard for
character representation. For example, the latest versions of Windows Vista and Mac OS X,
as well as all varieties of Linux, offer Unicode support. All web standards, such as the latest
versions of HTML and XML support Unicode, as well as the latest versions of Internet
Explorer and all Mozilla-based browsers. In addition, SQL databases such as the most
recent versions of Sybase, Oracle, and DB2 provide Unicode support.
Together with the display of multiple languages in Omnis, the use of Unicode encoding
affects the sort order of dynamic data, for example, in list variables, as well as the querying
and retrieval of data from Unicode compatible Server databases.

402

Omnis Data File Conversion

Omnis Data File Conversion


WARNING: YOU SHOULD MAKE A SECURE BACKUP OF YOUR OMNIS
DATA FILES BEFORE CONVERTING THEM IN THE UNICODE VERSION OF
OMNIS STUDIO.
When you access an Omnis data file you are asked to confirm that you want to convert the
data. After you select Yes, Omnis displays a dialog which offers two types of conversion:
Full
whereby a full conversion of the Character based data in you Omnis data file takes
place. The existing indexes are dropped and a new index of your data is built
Quick
whereby the indexes are dropped and rebuilt, but the Character data in you Omnis data
file is not converted. This is OK for files containing only 7 bit data: Omnis does not
check that the file contains only 7 bit data, so its your responsibility to know whether
or not it is safe to run this conversion process.
The full data file conversion mechanism converts the data in your Omnis data file and
rebuilds the indexes. When data file conversion takes place, all data marked as Character is
converted, including any characters >= 128. Note that in the case where character data is
stored in a binary or external file, for example, text stored in a document file, conversion of
this data does not take place.

Testing Data File Conversion


Omnis Studio can perform a full conversion of Omnis data files to Unicode, as described
above. If this is the first time you have used the Unicode version of Omnis, we suggest that
you make a secure copy/backup of your Omnis data file and convert one of the copies using
the Full conversion mechanism. We suggest that you check the results of the full
conversion carefully, making sure that the Character data has converted successfully and
that the indexes have been rebuilt successfully.
You may want to perform some regression tests on your application and data you should
normally do this with a new version of Studio, but when converting to Unicode Omnis, and
converting your data files, you need to be especially sensitive to possible data file and
indexing issues.

Data File commands


The Open data file and Prompt for data file commands have an existing option called
Convert without user prompts. If this is checked, and the new Full Unicode conversion
option is checked, no dialogs are displayed and your data is converted to Unicode using the
Full conversion process.

403

Chapter 11Unicode

DAMs
The DAMs provided with Studio 5.0 are able to function in Unicode or 8-bit compatibility
mode. This means that after converting your existing libraries for use with Studio 5.0, it is
possible to continue interacting with non-Unicode databases.
In 8-bit compatibility mode, all DAMs:
Return non-Unicode character data types via the $createnames() and $coltext attributes
Bind outgoing character variables using the database's non-Unicode data types
Convert all data inside outgoing character bind variables to single-byte characters
Define incoming character columns using the database's non-Unicode data types
Convert all data inside incoming character bind variables from bytes into characters

Switching to 8-bit compatibility mode


To switch to 8-bit compatibility mode, there is a session property $unicode which should be
set to kFalse from its default value of kTrue. This implementation allows multiple Unicode
and 8-bit session objects to exist side by side if required.

Character Mapping
This section is applicable to session objects operating in 8-bit compatibility mode only.
When reading data from a server database, Omnis expects the character set to be the same
as that used in an Omnis data file. The Omnis character set is based on the Mac OS
extended character set, but is standard ASCII up to character code 127. Beyond this value,
the data could be in any number of different formats depending on the client software that
was used to enter the data.
When assigned, the $maptable session property identifies files containing translation tables
for 8-bit character codes read into and sent out of Omnis. For example, suppose you are
working with a database that stores EBCDIC characters. In order to accommodate this
database, you should create an '.IN' map file that translates EBCDIC characters to ASCII
characters when Omnis in reading server data and a matching '.OUT' file that reverses the
process by converting ASCII to EBCDIC characters when Omnis is sending data to the
server.
Under Windows and Linux, Omnis uses the same character set as under Mac OS, so in the
general case, mixed platform Omnis applications should have no need for character
mapping. However, if the data in a server table was created by another software package,
running under Windows for example, the characters past ASCII code 127 would appear
incorrect when read using Omnis. In this situation the $maptable property should be used to
map the character set.
404

DAMs
There are two kinds of character maps: IN and OUT files. IN files are used to translate
characters coming from a server database into Omnis. OUT files are used to translate
characters that travel from Omnis back to a server database.

The Character Map Editor


The Character map editor is accessed via the Add-On tools menu item and enables you to
create character-mapping files. You can change a given character to another character by
entering a numeric code for a new character. The column for the Server Character for both
.IN and .OUT files may not actually represent what the character is on the server. This
column is only provided as a guide. The Numeric value is the true representation in all
cases.
To change a character, select a line in the list box and change the numeric code in the
Server Code edit box. Once the change has been recorded, press the Update button to
update the character map. You can increase/decrease the value in the Server Code edit box
by pressing the button with the left and right arrows. Pressing the left arrow decreases the
value, pressing the right arrow increases the value.
The File menu lets you create new character map files, save, save as, and so on. The Make
Inverse Map option creates the inverse of the current map, that is, it creates an ".IN" file if
the current file is an ".OUT" character map, and vice versa.

Using the Map Files


Establish the character mapping tables by setting the session property $maptable to the path
of the two map files. Both files must have the same name but with the extensions .IN and
.OUT and be located in the same folder. The $maptable property establishes both .IN and
.OUT files at the same time. For example:
Do SessObj.$maptable.$assign('C:\Program Files\TigerLogic\
Charmaps\pubs') Returns #F

In this example, the two map files are called "pubs.in" and "pubs.out".
The session property $charmap controls the mode of character mapping that is to be applied
to the data. Set the character mapping mode using a command of the form:
Do SessObj.$charmap.$assign(pCharMap) Returns #F

The potential values for the character mapping mode parameter pCharMap are:
kSessionCharMapOmnis
Use the internal Omnis character set.
kSessionCharMapNative
This is the default and specifies that the client machine character set is to be used.
kSessionCharMapTable
Use the character mapping table specified in the $maptable property. If the $maptable
property is not set and the application attempts to assign kSessionCharMapTable this
fails.
405

Chapter 11Unicode
If you wish to use the character mapping tables defined using the $maptable property, you
must set $charmap to kSessionCharMapTable.

Interpreting 8-bit Data


This section is applicable to the MySQL, PostgreSQL and Openbase DAMs which interface
with their respective client libraries using the UTF-8 encoding.
When operating in Unicode mode, it is possible to receive mixed 8-bit and Unicode data,
since UTF-8 character codes 0x00 to 0x7F are identical to ASCII character codes.
Where this data was created using the non-Unicode version of Omnis however, it is possible
that the data may contain ASCII extended characters. In this case, the Unicode DAM will
encounter decoding errors, mistaking the extended characters as UTF-8 encoded bytes.
This issue was not a concern for the non-Unicode version of Omnis Studio since extended
characters were always read and written as bytes, irrespective of the database encoding.
In order to avoid problems when upgrading to the Unicode version of Omnis Studio, it is
advisable to convert tables containing ASCII extended characters to UTF-8. This process is
simplified where the database character set is already set to UTF-8 (as is often the case with
MySQL). All that is required is to read and update each row in the table and repeat this for
all tables used by the application. In so doing, Omnis will convert the 8-bit data to Unicode
and then write the converted Unicode data back to the database.
In order to facilitate this within the DAM, the session property $validateutf8 is provided.
When set to kTrue (the default), any fetched character data is validated using the rules for
UTF-8 encoding. Where a given text buffer fails validation, it is assumed to be non-Unicode
data and is interpreted accordingly. When written back to the database, all character data
will be converted to UTF-8. Such updates will result in frequently accessed records having
their contents refreshed automatically.
By setting $validateutf8 to kFalse, validation is skipped and the DAM reverts to the
previous behavior, in which case extended ASCII characters should be avoided.
Aside from the issue of UTF-8 encoded data, the DAMs provided with Studio 5.0 are able
to retrieve non-Unicode data from non-Unicode database columns in either Unicode or 8-bit
compatibility mode. The DAM knows the text capabilities of each character data type and
assigns encoding values to each result column accordingly.
The difference in behavior when using 8-bit compatibility is that in compatibility mode, it is
also possible to write data back to non-Unicode columns.
In Unicode mode, the DAM assumes that it will be writing to Unicode compatible data
types and this will cause data insertion/encoding mismatch errors if the clientware tries to
insert into non-Unicode database columns.

406

DAMs

Character Mapping in Unicode Mode


Character mapping to and from the Omnis character set is also possible where session
objects are operating in Unicode mode. This was previously removed from the Unicode
DAMs since it provided compatibility between the various 8-bit character sets. Where
Unicode DAMs encounter 8-bit data however, it is necessary to indicate the character set
used by the data. For this reason the session $charmap property can be used to indicate that
fetched 8-bit data uses either:
kSessionCharMapRoman
Use the Mac Roman character set to interpret the characters
kSessionCharMapLatin1
Use the Windows/Linux character set to interpret the characters

Fetching Data to a File


The $fetchtofile() method has the iEncoding parameter, as follows:
Do StatementObj.$fetchtofile(cFilename [,iRowCount=1]
[,bAppend=kTrue] [,bColumnNames=kTrue]
[,iEncoding=kUniTypeUTF8/kUniTypeLatin1])
returns Long integer

where iEncoding is an optional parameter specifying the type of encoding to be used. It


should be one of the Unicode type constants and defaults to kUniTypeUTF8. The
corresponding Unicode Byte Order Marker (BOM) is written to the beginning of the file
when the file is empty or when bAppend is set to kFalse.

407

Chapter 11Unicode

Server Specific Programming


Certain DAMs, namely DAMORA8 and DAMODBC, also provide session properties
which allow mixing of Unicode and 8-bit data when the DAM is operating in Unicode
mode.

Oracle DAM
This section summarizes recent changes made to the Unicode Oracle Object DAM designed
to enable insertion and retrieval of mixed ANSI and Unicode character types.
In the case of Oracle 8i and later, these data types are:
CHAR

Fixed single-byte character data, limited to 2000 bytes.

NCHAR

Fixed multi-byte character data, limited to 2000 bytes.


(1000 UCS-2 encoded characters)

VARCHAR2

Varying length, single-byte character data, limited to 4000 bytes.

NVARCHAR2

Varying length, multi-byte character data, limited to 4000 bytes.


(2000 UCS-2 encoded characters)

CLOB

Character Large Object- single-byte character data.

NCLOB

National Character Large Object- multi-byte character data.

LONG

Varying length, single-byte character data, limited to 2GB.


Supported for backward compatibility only.

By default, the Unicode Oracle DAM maps all Omnis character data to the NVARCHAR2
and NCLOB data types, dependent on the field length of the Omnis bind variable. However,
the Oracle DAM provides session properties which affect the Omnis to Oracle data type
mappings:
$nationaltonvarchar
If set to kTrue, Character and National data types are treated differently when being
inserted to VARCHAR2 / NVARCHAR2 columns. The National character subtype
will be used with Unicode data, whilst the Character subtype will be reserved for nonUnicode data.
$nationaltonclob
If set to kTrue, large Character and National data types are treated differently when
being inserted to CLOB / NCLOB columns. The onus is upon the developer not to put
Unicode characters into Character subtypes when using these properties; otherwise data
insertion/encoding mismatch errors will occur.
$maxvarchar2
Sets the byte limit above which Omnis character fields will be mapped to

408

Character Normalization
CLOB/NCLOB data types as opposed to VARCHAR2 / NVARCHAR2 columns. The
maximum value is 4000 bytes.
$longchartoclob
If set to kTrue (the default), Omnis large character fields > $maxvarchar2 in byte length
will be mapped to the CLOB/NCLOB data type. If set to kFalse, the LONG data type is
used.
Reading Unicode and Non-Unicode Data
The Oracle DAM automatically detects the data type of retrieved character columns and
converts the data accordingly. There is no need to modify any properties in order to retrieve
mixed ANSI and/or Unicode Data.

ODBC DAM
The ODBC DAM provides the $nationaltowchar session property.
By default, Omnis Character and National fields are mapped to the SQL_WCHAR,
SQL_WVARCHAR and SQL_WLONGVARCHAR data types. By setting
$nationaltowchar to kTrue only National fields will be mapped to these types (to the
equivalent server data types) and Character fields will be mapped to SQL_CHAR,
SQL_VARCHAR and SQL_LONGVARCHAR as determined by the Omnis field length.
Character fields mapped in this way are subject to data loss/truncation where such fields
contain Unicode characters. When setting this property, please note that Unicode data types
usually have precision limits half that of their corresponding ANSI data types. For example,
this is 8000 for the SQL Server VARCHAR() data type but 4000 for NVARCHAR().
$nationaltowchar affects both the text returned by the $createnames() method and the
binding of input parameters.

Character Normalization
Originally, Unicode was a 16-bit character set. It has subsequently been extended to include
code point values up to and including U+10FFFF. It is not expected that it will be extended
any further. Windows and Mac OS X still represent Unicode character strings using arrays
of Short (16-bit) integers. This is not a problem, because the UTF-16 standard allows code
points U+10000 and greater to be represented by pairs of 16-bit values (each member of the
pair occupies space in the 16-bit range that is not used for code points). This representation
is referred to as a surrogate pair.
Internally Omnis uses UTF-32 to represent code points, that is, each code point occupies 32
bits, and the value of each code point is between 0 and U+10FFFF inclusive. This allows
for straightforward processing of character strings, since every code point occupies the
same space in memory.
Unicode allows a significant number of characters to be represented by more than one
sequence of code points. For example, consider the letter E with circumflex and dot below,

409

Chapter 11Unicode
a character that occurs in Vietnamese (). This character has five possible representations in
Unicode:
1. U+0045 Latin capital letter E
U+0302 combining circumflex accent
U+0323 combining dot below
2. U+0045 Latin capital letter E
U+0323 combining dot below
U+0302 combining circumflex accent
3. U+00CA Latin capital letter E with circumflex
U+0323 combining dot below
4. U+1EB8 Latin capital letter E with dot below
U+0302 combining circumflex accent
5. U+1EC6 Latin capital letter E with circumflex and dot below
A character represented by more than one code point is referred to as a composite
character. A character represented by a single code point is referred to as a pre-composed
character.
As far as the end-user is concerned each of these representations usually needs to be treated
identically. This leads to some interesting consequences for Omnis. These are discussed in
the following sections. Note the term end-user character means the character that the enduser is working with in the example above, the end-user character is .
Normalization of a Unicode character string converts the string into a standard, defined
format. Once normalized, a Unicode character string has only one possible representation,
thereby making it possible to compare it with other character strings, and produce results
useful to the end-user. The Unicode standard recommends two forms of normalization.
These are:
1. Canonical decomposition, referred to as NFD:
Pre-composed characters are replaced by their equivalent composite characters;
Composite characters are replaced with a single fixed composite representation.
2. Canonical decomposition followed by canonical composition, referred to as NFC:
After carrying out NFD, all composite characters are replaced with their pre-composed
equivalent, where one exists.
Omnis provides two functions to normalize character strings:
nfd(string) carries out canonical decomposition on the string and returns the
normalized string.
nfc(string) carries out canonical decomposition followed by canonical composition on
the string and returns the normalized string.
These functions are not available in client-side web client methods.
410

Character Normalization

Comparing Text
Omnis uses two types of comparison for character strings:
Comparison of the UTF-8 values of the strings. This is called Character comparison.
Comparison according to the rules for the locale specified via the localization data file;
prior to comparison, the input data is normalized. This is called National comparison.
National comparison is more likely to produce results that the end-user would expect.
Note that upper casing used in conjunction with national comparison may not have an
effect, since sometimes the rules for the locale ignore the case of the characters.
The natcmp() function uses national comparison. Note that natcmp() is not available in
client-side web client methods.
Omnis compares text for many different reasons, and in many different places. Key areas
are:
Sorting lists
Searching lists
Manipulating data file indexes
Expressions, for example the test on an if statement
Omnis supports two types of character variable character and national.

Sorting Lists
When using the character type, Omnis uses character comparison.
When using the national type, Omnis uses national comparison.

Searching Lists
When using the character type, Omnis uses character comparison.
Searches that directly use a character column of national type use national comparison.
Other searches, for example searches using a calculation, will behave as if they are
operating on normal character data. However, you can use natcmp() as part of the
calculation, in order to use national comparison.

Manipulating Data File Indexes


Indexes for national fields use national comparison.

Expressions
To ensure the correct behavior of expressions that test the value of character variables, you
must either normalize their value first using nfc() or nfd(), or you must use the natcmp()
function.

411

Chapter 11Unicode

Drawing Text
Depending on the font and operating system you use, different representations of the same
end-user character may not always be drawn in the same way. The same applies if you try to
use strings that require surrogate pairs. Generally speaking, you will get the best results if
you normalize the text using nfc(), as the issues generally occur with composite characters.

Entering Text
Wherever possible, you should use the nfc() normalization form for data that is to be edited.
If composite characters are present in the data, multiple left or right arrow key presses are
required to skip a composite character, and also clicking and selecting in the text will
highlight an area which when copied to the clipboard might not exactly contain what
appeared to be highlighted.
Omnis performs NFC normalization on character data pasted from the clipboard when
running in the thick client (runtime); no normalization occurs when pasting characters into a
remote form when using the web client.

Character Translation
The following functions allow you to translate a specified character in a string to its
Unicode value and to allow the reverse.
unicode(string,position[,returnhex])
returns the Unicode value of the character at the specified position in the string. The
first position in string is 1. If Boolean returnhex is true (default false) it returns a hex
string representing the value, of the form 'U+h'.
unichr(num1[,num2]...)
returns a string formed by concatenating the supplied Unicode character codes. Each
code is either a number or a string of the form 'U+h',where h is 1-6 characters
representing a hexadecimal value.
These functions are available in client-side methods as well as the thick client, but will
generate an error if used in the non-Unicode version of Omnis.

Unicode Clients
Locale Identifier
The locale()function returns the Locale Identifier (LCID) for the current client
machine/operating system. As well as the language of the machine, the Locale Identifier
specifies the decimal, thousand and list separators, currency values, units of measurement,
412

Unicode Data Handling


date formats, and character sort order. The Locale is specified at the operating system level
and is in the form language_country, where language is the ISO639 language name, and
country is the ISO3166 country name. For example, the Locale for the UK is en_GB. On
Mac OS X, there may be other information, such as a script code, between the language and
country (this is because OS X uses ICU locales).

Unicode Data Handling


The uniconv() function allows you to translate Unicode character data from one type to
another. The syntax is:
uniconv(srctype,src,dsttype,dst,bom,errtext)

The function converts src, and stores the result in dst. It returns zero for success, or a nonzero error code together with error text in errtext. Src and dst are either binary or character
variables, depending on the values of the srctype and dsttype.
srctype and dsttype are one of the kUniType... constants (see below).
Bom is Boolean: if true, dst has a Unicode Byte Order Marker (BOM) if relevant for the
destination type.
The kUniType... constants are as follows:
kUniTypeAuto
The source encoding is automatically detected from the conversion source; possible
encodings are identified by the remaining kUniType... constants (allowed only for the
source type).
kUniTypeUTF8
The data is stored in a binary variable and contains Unicode character data encoded
using UTF-8
kUniTypeUTF16
The data is stored in a binary variable and contains Unicode character data encoded
using UTF-16LE if the machine is little-endian, or UTF-16BE if the machine is bigendian. Useful when writing cross-platform code that interacts with the OS.
kUniTypeUTF16BE or kUniTypeUTF16LE
The data is stored in a binary variable and contains Unicode character data encoded
using UTF-16BE (big-endian) or UTF-16LE (little-endian)
kUniTypeUTF32
The data is stored in a binary variable and contains Unicode character data encoded
using UTF-32LE if the machine is little-endian, or UTF-32BE if the machine is bigendian. Useful when writing cross-platform code that interacts with the OS.

413

Chapter 11Unicode
kUniTypeUTF32BE or kUniTypeUTF32LE
The data is stored in a binary variable and contains Unicode character data encoded
using UTF-32BE (big-endian) or UTF-32LE (little-endian)
kUniTypeNativeCharacters
The data is stored in a binary variable and contains a stream of bytes, where each byte
is a character in the Latin 1 character set for the machine (Ansi on Windows,
MacRoman on the Mac, ISO-8859-1 on Unix
kUniTypeCharacter
The data is stored in a character variable. Note this constant has been moved since
the last Unicode build, so you need to re-enter it in your code.
kUniTypeAnsi
The data is stored in a binary variable, and contains character data where each byte is
encoded using the specified ANSI code page. A range of constants are provided to
cater for most world or regional languages, including Cyrillic, Greek, Hebrew, Arabic,
Thai, and so on
kUniTypeISO8859...
The data is stored in a binary variable, and contains character data where each byte is
encoded using the specified ISO 8859 code page.
There are two sys() functions to assist OEM conversion when using the uniconv() function.
sys(218) modifies OEM conversion to map CR to CR and LF to LF.
sys(219) reverts to the original mapping for the OEM code page.

Formfile
The $filereadencoding and $filewriteencoding properties have been changed. In previous
versions of Omnis Studio, the Formfile component defined kFFEncoding constants.
These constants should not now be used, and you are advised to use the kUniType
constants to identify the file encoding. Formfile has been extended, so that you can use any
of the kUniType... constants except kUniTypeCharacter for the $filereadencoding property,
and any of the kUniType... constants except kUniTypeAuto and kUniTypeCharacter for the
$filewriteencoding property.
In addition, there is also a kUniTypeBinary constant to identify files that are to be treated as
raw binary data.
Code that uses the old kFFEncoding constants should continue to work.

414

Import/Export and Report File Encoding

Fileops
The Fileops component has two methods, $readcharacter() and $writecharacter() which
allow you to read and write Unicode character data from and to a file.
$readcharacter(encoding,variable)
reads all data from a file containing character data into variable; encoding is one of the
kUniType constants (listed above), identifying the encoding of the file.
$writecharacter(encoding,variable)
replaces the contents of the file with the character data stored in variable; encoding is
one of the kUniType constants, identifying the encoding of the file.
For $readcharacter, specify the encoding as any kUniType... constant except
kUniTypeBinary and kUniTypeCharacter.
For $writecharacter, specify the encoding as any kUniType... constant except
kUniTypeAuto, kUniTypeBinary and kUniTypeCharacter.
Note the $readcharacter() and $writecharacter() methods use the kUniType constants and
not the kFFEncoding constants which should not now be used.

Mixing Char & Binary data


You cannot concatenate a Character variable to a Binary in the Unicode version of Omnis
Studio. The correct method is to use $readfile to read the file into a Binary variable, and
then parse the binary variable. Assigning Character to Binary and vice-versa is likely to
cause problems, including data corruption, and should therefore be avoided.

Import/Export and Report File


Encoding
There are a number of properties that control the encoding of import text files, export files,
and report data written to text files and the port. These are:
$importencoding
The encoding used for imported data when importing from port, or when the import file
does not have a Unicode Byte Order Marker (BOM). Any of the kUniType... constants,
except kUniTypeAuto, kUniTypeCharacter, kUniTypeBinary and the
kUniTypeUTF32 values.
$exportencoding
The encoding used for exporting data and printing to port or text file. Any of the
kUniType... constants, except kUniTypeAuto, kUniTypeCharacter and
kUniTypeBinary.

415

Chapter 11Unicode
$exportbom
If true, and the $exportencoding preference identifies a Unicode encoding, a Unicode
BOM is output at the start of the output file.
These properties can be found in the Omnis preferences ($root.$prefs). In a multi-threaded
server, there is a separate value of each of these properties for each thread.

416

Localizing Your Libraries

Chapter 12Localization
Note: the following section describes a localization method that can only be used for
Window classes and Remote forms that use the Web Client plug-in. For all new libraries
that use the JavaScript Client we urge you to use the localization method described in the
Creating Web & Mobile Apps manual.
If you are developing Omnis applications for an international market, you may want to
translate the text and labels in your libraries into another language or support multiple
languages. Omnis provides tools for localization of your libraries via the String Table tab on
the Catalog window and via the String Table editor in the Add-ins submenu of the Tools
menu.
As well as translating your Omnis libraries, you can translate the majority of the text and
strings that appear in the Omnis Runtime environment (the Omnis.exe) and the Omnis Web
Client. You can localize various language dependent strings in the Omnis executable itself,
such as the days of the week.

Right to Left Data Entry


In addition to the localization or translation functionality in Omnis Studio, you can force
data entry fields to display their data from right to left, for example, to support text entry on
Arabic machines. The $righttoleft property allows data in single- and multi-line edit fields
to scroll from the right to the left. When this property is enabled for a multi-line field, the
vertical scrollbar is displayed on the left of the field.

Localizing Your Libraries


Omnis contains an external package called StringTable that contains a special String label
object and a set of functions that allow you to dynamically change the language of text
labels in your Omnis application.
You can use the String Table Editor in Omnis to create tables containing a matrix of strings
or words for any number of languages. String tables and the functions in the StringTable
package allow you to load the text for fields, buttons, and text labels when the window is
opened, and then change the language of the text while the window is open.
The String Table Editor allows you to translate a whole list of strings (stored in the first
column of your string table) into one or more languages automatically. For example, you
could add English labels to a window or remote form, add the text for these labels to a
string table, and translate all the labels to French, German, and Italian, with a single mouse
click. The String Table Editor uses the translation tools provided by Google Translate to
translate the text in your string tables automatically.
417

Chapter 12Localization

Using String Labels


First you need to create your window or form in your application that you wish to display in
multiple languages. If you are enabling an existing window for dynamic label and text
translation, you will need to replace existing text labels with the special String Label
external component from the StringTable package. You can use standard fields and
buttons.

Locating the StringLabel component


For window classes
the StringLabel object is located in the Background Components group in the
Component Store. The StringTable component is pre-loaded for window classes so you
dont need to load it by right-clicking on the Component Store.
For remote forms (using the Web Client plug-in only)
the StringLabel object is located in the WEB Background Objects group in the
Component Store. If the object is not shown in the Component Store, right-click the
Component Store, select the External Components option, and load the String
Label object (FORMSTRG) from the Form Background Components node in the list.
To create String labels

Open your remote form and open the Component Store (press F3)
Click on the Background Components or WEB Background Objects group in the
Component Store toolbar and drag the String Label component onto your window or
remote form
Open the Property Manager (F6/Cmnd-6), click on the Custom tab, and enter a suitable
label in the $rowid property; the row ID can be a number or string
Create the other labels for your window or form using the String Label component, and
assign unique labels in the $rowid property for each one

The string label object can display single or multiple lines of text.
It is also possible to translate the text for pushbuttons, check boxes and the contents of lists
that may appear in your window or form. To identify these objects in the string table and
your Omnis code you should make sure the objects have a suitable text string specified in
the $name property. The text in the $name property of an object should be used as the row
ID in the string table and also used in your code to reference the text.

418

Localizing Your Libraries

Editing String Tables


Having created the string labels and buttons in your window or remote form, you need to
create a String Table that contains all the alternative text for each object in the different
languages you wish to support.

Note for existing users


In previous versions of Omnis Studio, the first column of a string table was labeled ID but
in Studio 5 is now called STRINGID. This is because ID is the ISO 639 code for
Indonesia, and the Studio 5.0 localization features use ISO 639 codes to identify the
language columns, so ID could no longer be used. Old string tables, where column one is
called ID will usually still work, unless of course you are using ID to represent Indonesia
in one of the language columns.
To create a string table

Open the String Table Editor from the Tools>>Add-Ons menu


Click on New to clear the table and create a new file; you can click on Save to save the
new string table; the file should have the .stb file extension and can be located in the
same folder as your library

Note: Your Omnis library cannot be called STRINGTABLE.


The first column in the new string table is called STRINGID: do not rename this column
since this will contain the object rowIDs used to identify the strings in the table.

Rename the second column by clicking in the column and selecting the Rename
Column option from the Columns menu; name the column using the two-letter ISO 639
language code for your native or default language, e.g. enter EN if your string labels
and buttons contain English
Next you need to add a row for each string label or button you have used in your
window(s) and/or remote form(s) in your application, entering the row IDs and button
names you have used to identify these objects in the STRINGID column

You can tab to the end of the row to create a new row or click the Add Row button and
enter the Row ID for the next table entry; continue adding rows for each label or object you
wish to translate.

Add a column for each language you wish to support in your application, using the twoletter ISO 639 language code to name each column, e.g. the third column could be
named FR to support French, the fourth column could named DE to support German,
and so on
Next click on the Translate button, select the Translate from column and the
Translate to columns; note the Translate to list allows multiple selections to allow
419

Chapter 12Localization
you to translate to multiple languages, or you can press Ctrl/Cmnd-A to select all lines
(except the column selected in Translate from)

Click the Translate button and Omnis will translate all the strings; note this may take a
few minutes if you have many rows and columns in your string table

The following example shows a String Table for a remote form that has a number of string
labels and pushbuttons. The English strings are in the second column, while the French and
German strings were added automatically using the Translate option.

Then you need to save and close the string table


Finally, click on the background of your window or form, open the Property Manager
(F6), and set the $stringtabledata property to the name of your string table; you can
click on the property dropdown and navigate to your string table

Under certain circumstances you can use the STRINGID column in your string table as your
default language, for example, if you have used the exact label names in the STRINGID
column rather than some other rowID. In this case, you need to specify the Locale of your
STRINGID column in the Translate dialog, using the two-letter ISO 639 language code, to
identify its language.

Accessing String Tables via the Catalog


String Tables can be accessed and edited via the String Table tab in the Catalog (F9)
window. Your own string tables for windows and remote forms will appear in the Catalog
window when the window or form is the top design class.
Omnis Studio 5 has two new string tables that allow you to translate various built-in string
resources in the Omnis executable, and the string resources in the Web Client. These are
visible in the Catalog and can be edited in the String Table Editor from there.

420

Localizing Your Libraries

String Table Functions


The StringTable package contains a number of functions that allow you to load string
tables, load text items from a table, and replace the text in the windows in your application.
The following methods are available:
$colcnt()
StringTable.$colcnt([cTableName]) returns the number of columns in string table
cTableName, or an error code which is less than zero
$getcolumnname()
StringTable.$getcolumnname([cTableName]) returns the current column name for the
string table specified by cTableName, or an error code which is less than zero
$getcolumnnumber()
StringTable.$getcolumnnumber([cTableName]) returns the current column number for
the string table specified by cTableName, or an error code which is less than zero
$gettablelist()
StringTable.$gettablelist(lList) populates a single column lList with the loaded string
table names; define lList to have a single character column before calling this method
$gettext()
StringTable.$gettext(cRowID) returns the text from the cell specified by cRowID for
the current column, or an error code which is less than zero
$loadcolumn()
StringTable.$loadcolumn(cColumnNumber|Name,cTableName,cPathname) loads
column cColumnNumber|Name from string table at cPathname into table cTableName.
Returns kStringTableOK or an error code which is less than zero
$loadexistingtablefromlist()
StringTable.$loadexistingtablefromlist(cTableName,lList) replaces an existing string
table with the content of a list. Returns kStringTableOK or an error code which is less
than zero
$loadlistfromtable()
StringTable.$loadstringtable(cTableName,cPathname) loads string table from file
cPathname, and gives it the name cTableName. Returns kStringTableOK or an error
code which is less than zero
$loadstringtable()
StringTable.$loadstringtable(cTableName,cPathname) loads string table from file
cPathname, and gives it the name cTableName. Returns kStringTableOK or an error
code which is less than zero
$loadtablefromlist()
StringTable.$loadtablefromlist(cTableName,cPathname,lList) creates a string table
from a list. Returns kStringTableOK or an error code which is less than zero
421

Chapter 12Localization
$removestringtable()
StringTable.$removestringtable(cPathname) deletes the string table file specified by
cPathname. Returns kStringTableOK or an error code which is less than zero
$rowcnt()
StringTable.$rowcnt([cTableName]) returns the number of rows in string table
cTableName, or an error code which is less than zero
$savestringtable()
StringTable.$savestringtable(cTableName) saves the string table specified by
cTableName. Returns kStringTableOK or an error code which is less than zero
$setcolumn()
StringTable.$setcolumn(cColumnNumberOrName) sets the current column. Returns
kStringTableOK or an error code which is less than zero
$unloadall()
unloads all string tables from memory.
$unloadstringtable()
StringTable.$unloadstringtable(cTableName) unloads the string table cTableName
from memory. Returns kStringTableOK or an error code which is less than zero
The following functions apply to string tables for remote forms and are available for
execution in client methods only:
stgettext()
StringTable.stgettext(id) returns the string with the specified id from a string table, or
empty if the lookup fails. id can be prefixed with 'TABLENAME.', or must be an id for
the string table of the current form.
stgetcol()
StringTable.stgetcol(table) returns the name of the current column for string table table
stsetcol()
StringTable.stsetcol(table,col) sets the current column for lookups from string table
table to the column with name col and returns Boolean true for success.

422

Localizing Your Libraries

Programming String Tables


The following method loads a string table with the name Lang.stb and sets the column
containing the English text as the current column.
; custom method $loadStringTable
Calculate lvpath as sys(10)
Do
FileOps.$splitpathname(lvpath,lvdrive,lvdirname,lvfilename,lvfile
ext)
Calculate lvpath as con(lvdrive,lvdirname,"Lang.stb")
Do StringTable.$loadStringTable(iTableName,lvpath) Returns lnum
If lnum<>kStringTableOK
OK message Error (Icon) {The Language String Table "Lang.stb"
could not be loaded.}
Quit method lnum
End If
; Select the English Language
Do StringTable.$setColumn("English") Returns lnum
Quit method lnum

Having loaded the string table and specified the current column, the following method can
be used to load the text or string values into the appropriate field labels, buttons, and lists in
a data entry window. Note that the IDs for each object are stored in custom constants that
are defined in the the Startup_task in the library.
; custom method $loadFields
; Define the button and group box descriptions using $getText
Do StringTable.$getText(kPrintButton) Returns lval
Do $cwind.$objs.PrintButton.$text.$assign(lval)
Do StringTable.$getText(kLanguageButton) Returns lval
Do $cwind.$objs.LanguageButton.$text.$assign(lval)
Do StringTable.$getText(kEmpTitle) Returns lval
Do $cwind.$objs.stEntry_1022.$text.$assign(lval)

423

Chapter 12Localization
The next section of the method defines the dropdown lists for Sex (male/female) and
Marital Status by loading the relevant entries from the current string table.
Set current list iSex
Define list {iField}
Do StringTable.$getText(kMale) Returns iField
Add line to list
Do StringTable.$getText(kFemale) Returns iField
Add line to list
Calculate iSex.$line as 1
Set current list iStatus
Define list {iField}
Do StringTable.$getText(kMarried) Returns iField
Add line to list
Do StringTable.$getText(kSingle) Returns iField
Add line to list
Calculate iStatus.$line as 1

Within your application you need to provide some way for the user to select and change the
language setting. This could be done using a separate window containing a list of available
languages and a button to set the selected language. The following method gets all language
column names from the Lang String Table and puts them into an Omnis list.
; custom method $loadList
Set current list iLang
Define list {iLangField}
; Save the current column number
Do StringTable.$getColumnNumber() Returns lnum
; Build a list of all column names in the String Table.
Do StringTable.$colCnt() Returns maxcol
; Start from column 2 as column 1 is reserved for String Table IDs
For lcount from 2 to maxcol step 1
Do StringTable.$setcolumn(lcount)
Do StringTable.$getcolumnname() Returns iLangField
Add line to list
End For
Do StringTable.$setColumn(lnum)
Calculate iLang.$line as pLine

When the user selects a language from the list, they should click a button with the following
method which changes the language of the text on itself and the data entry window.

424

Localizing Your Libraries


On evClick
;; Event Parameters - pRow( Itemreference )
Set current list iLang
Calculate lval as ((iLang.$line)+1)
; need to offset by 1 since col1 in string table has the rowID
Do StringTable.$setColumn(lval)
Do StringTable.$getText(kLangTitle) Returns lval
Do $cwind.$objs.stLang_1016.$text.$assign(lval)
Do StringTable.$getText(kSetLanguage) Returns lval
Do $cwind.$objs.SetLang.$text.$assign(lval)
Do $root.$iwindows.stEntry.$loadFields
; this line runs the $loadFields method again (see above) to
change the objects in the data entry window
Do method $loadList (iLang.$line)
; this line reloads the language list in the new language
Do method $translateList
Do method $redrawAll

The following method translates the language list depending on the Language selected. The
code uses the String Table column headings to look up corresponding IDs from within the
table itself.
; custom method $translateList
Set current list iLang
Calculate lnum as iLang.$line
Calculate lrowcnt as iLang.$linecount
For lcount from 1 to lrowcnt step 1
Do StringTable.$getText(iLang.[lcount].iLangField)
Returns iLang.[lcount].iLangField
Calculate iLang.$line as lcount
End For
Calculate iLang.$line as lnum

Finally you need a method to redraw all the fields and text labels on any open windows or
forms.
; custom method $redrawAll
Do $iwindows.$first() Returns ref
While ref
Do StringTable.$redraw(ref.$hwnd)
Do $iwindows.$next(ref) Returns ref
End While

425

Chapter 12Localization

Localizing Remote Forms


The String Label object is available for remote forms, and together with string tables, allows
you to localize your applications running in the Omnis Web Client. See the previous section
for details about how to create string labels and string tables; the technique is the same for
remote forms.
In Omnis Studio 5, remote form classes have a new property called $stringtabledata. The
contents of this property is the data, in list format, from a standard Omnis string table. To
populate $stringtabledata in the IDE, you can click on the droplist button on the property in
the Property Manager, and select a string table file. When you press OK, Omnis takes a
copy of the string table data and stores it in the class. If you cancel the dialog, Omnis asks if
you wish to clear the data from the class, which is a convenient way to clear the contents of
$stringtabledata.
When the web client creates an instance of the remote form class, on the client, it
automatically loads the string table data as a client-side string table, and sets the
string table name to the remote form class name.

The column names in the string table must be:


STRINGID for column 1 this is the standard for string tables, and the name cannot be
changed.
A two character ISO 639 language code for the second and subsequent columns; for
example, en for English, de for German, fr for French.
When the client loads a new string table (because a remote form is being instantiated in
some way), it uses the operating system locale of the client to locate the string table column
to use for lookups. You can override this behavior by setting the remote task instance
property $stringtablelocale to a two character ISO 639 language code to use instead of the
client operating system locale, but you can only do this in $construct of the remote task. If
there is no column in the string table for the desired locale (specified in $stringtablelocale),
lookups default to using column 2.
The $rowid property of a remote form string label object can refer to one of the Web Client
string tables. If $rowid is not prefixed with a table name (remote form name), then the string
must be in the string table for the remote form containing the object.
Any character string property of a remote form control can be specified as $st.id (note that
$st is not notation; it is just a special prefix recognized by the client). This tells the client to
lookup id in the string tables for the client, and set the property value to the result of the
lookup. The $rowid rules regarding the presence of a table name prefix also apply in this
case. Note that when you get a property set in this way, the result is the result of the lookup,
not $st.id.
There is a new remote form property called $stringtabledesignform which allows you to
access the string table in the Catalog (F9) windows while designing the remote form.

426

Localizing Your Libraries


There are three new Client String Table functions, available for execution in client
methods only:
stgettext(id)
returns the string with the specified id from a string table,or empty if the lookup fails. id
can be prefixed with 'TABLENAME.',or must be an id for the string table of the current
form.
stgetcol(table)
returns the name of the current column for string table table
stsetcol(table,col)
sets the current column for lookups from string table table to the column with name col
and returns Boolean true for success.

Remote tasks: $construct()


There is also a new column, ClientLocale, in the row variable parameter passed to
$construct() of the remote task. This contains the locale for the client, as returned by the
locale() function; the first two characters are the ISO 639 language code of the client.

Remote Menu Lines


You can set the text for a remote menu line to $st.id. The lookup occurs when the menu is
built on the client, before any event processing for the menu.

Tooltips
You can use the $st. lookup notation to lookup text from a string table to fill out the $tooltip
property for a field.

Decimal point character


The decimal point character for display and entry on the JavaScript Client is the character
for the current locale (either set by the current locale of the browser, or overridden using
$ctask.$stringtablelocale).

427

Chapter 12Localization

Localizing Omnis
In order to provide a completely foreign version of your Omnis application, you may need
to translate various resources that appear in Omnis itself (rather than strings that appear in
your libraries, as described in the previous section). This applies equally to applications that
run on the desktop using the Omnis executable (Runtime), and applications that run on the
Internet using the Omnis Web Client: you can translate string resources in the Omnis
runtime and in the web client.
Omnis Studio 5 introduces two new String Tables that allow you to translate:
Various built-in string resources in the Omnis executable, and
String resources in the Web Client.
The new String Tables can be accessed via the String Table tab in the Catalog (F9) window
and are edited using the String Table editor.
In addition, the Localization Library (omnisloc.lbs) is still available in the Local folder for
you to translate further string resources in the Omnis executable.

Localizing Built-in Client Resources


The built-in resources comprise the string resources, and the strings in dialogs, in the Omnis
core, externals and external components. Omnis has two new string tables used for the
translation of built-in and web client resources. The new tables are located in the Local
folder of the main Omnis tree, and are:
studio.stb
containing translations of text strings for the fat client, comprising dialogs, components,
and so on
client.stb
containing translations of text strings for the Omnis Web Client
These string tables can be edited using the String Table Editor. However, there are some
special rules regarding their structure: the STRINGID column is the exact value of the builtin resource text and cannot be changed; the other columns contain the translations of the
built-in resource text, and they are named using a 2 character ISO 639 language code, in
lower case.
Usually, there is no column for en (English), because the built-in resources are English. If
you are using a mixture of languages in the built-in resources, then you can add a column
for en. As a result, you will have cases where the STRINGID and language column for
the built-in resource would have the same value. To avoid duplicating the value in the
language column, you can enter * for that column, meaning the string does not need
translating from its STRINGID.

428

Localizing Omnis
When reading a string resource, Omnis looks up the string value in the string table, and if
present, it replaces the string value with the translation. If no translation is available, the
string remains unchanged. The string value lookup is case-sensitive, allowing the translation
to contain the correct case for the translated text.
Omnis loads the studio.stb string table when it starts up, and when $root.$prefs.$language
changes, and the appropriate language version of the resources is loaded. The column used
for translations is the ISO 639 language component of the locale stored in the current
language record. This is also stored in a small text file (locale.txt) in the Local folder of the
Omnis tree, to cater for the fact that the string table is loaded sooner in the life of Studio
than the localization data.
When a web-based client connects, Omnis sends client.stb to the client; this is handled via
the cache, so it will not always be sent. The client loads client.stb, and uses the column
corresponding to the client locale to obtain translations (the client locale can be specifically
set using $cinst.$stringtablelocale for the remote task instance, or it can be allowed to
default to the locale of the client machine).

Editing the Built-in Client Resources


You can open and edit the studio.stb and client.stb string tables via the Omnis Catalog (F9)
window. You can click on the String Table tab in the Catalog, and right-click on the string
table you wish to edit.

Local Language
The locale() function for the fat client now has an optional Boolean parameter, which when
passed as kTrue, causes it to return the locale field value for the current
$root.$prefs.$language.

429

Chapter 12Localization

Localizing the Omnis Runtime


Developers and distributors in non-English speaking countries may need to localize the
Omnis program (runtime) itself. You can localize the following Omnis internal items:
The names of the days of the week
The names of the months of the year
Separator characters
The text for Yes/No, OK/Cancel, True/False, Am/Pm and On/Off
The national sort ordering
The date ordinal suffixes

Storage of Localization Data


All libraries share the same set of data, stored in an Omnis data file or localization database
called OmnisLOC.DF1, located in the Omnis local folder.
OmnisLOC contains a data slot for configuration data; each record in that slot contains a
complete set of data corresponding to a particular language. It also contains a data slot with
a single record, which identifies the current language, that is, the current set of configuration
data.

The Localization Data


The following items are stored for each language.

Days of Week
This comprises 2 strings for each of the 7 days of the week, allowing for a full name such as
Wednesday, and an abbreviated name such as Wed.
If a day of the week item is empty, Omnis will read its value from the operating system.

Months of Year
This comprises 2 strings for each of the 12 months of the year, allowing for a full name such
as August, and an abbreviated name such as Aug.
If a month item is empty, Omnis will read its value from the operating system.

430

Localizing the Omnis Runtime

Separators
These comprise the following:
The decimal point used for all numeric fields. If this item is the character 0 (zero),
Omnis will read the decimal point character from the operating system.
The thousands separator used for numbers. If this item is the character 0 (zero),
Omnis will read the thousands separator character from the operating system.
The function parameter separator
The decimal point used when importing data
The field separator used when importing
The sequence used for quoting names in the notation

Standard Text Strings


These comprise the strings for Yes and No, OK and Cancel, True and False, AM and PM,
and On and Off. If the value of the AM or PM text is the single character 0 (zero), Omnis
will read the text from the operating system.

Locale: National Sort Ordering


The ISO 639 language code in the Locale field is used to define the sort ordering for
National fields. The Use Locale For Defaulted Items check box below the Locale field
determines the locale used for language items that have been left empty, so that they get a
default value from the system:
1. If the Use Locale check box is checked, default values come from the locale stored in
the language record.
2. If it is not checked, default values come from the operating system default locale on the
client machine.

Date Ordinal Suffixes


You can localize the date ordinal suffixes which are the strings that can be appended to a
day number to result in language specific days such as 1st, 2nd, 3rd, 4 th, etc. You can edit
the date ordinal suffixes field on the Text Strings tab of the localization library language
settings window.
For English, the value of the date ordinal suffixes field is:
th$1st$2nd$3rd$21st$22nd$23rd$31st$

If you leave the field empty, then no suffix is applied, otherwise, the string before the first $
is the default suffix, and the remaining $-separated strings are a day number followed by its
suffix. There must be a trailing $.
To see the suffix used for a particular date you can use the function call dat(date,d).

431

Chapter 12Localization

The natcmp() function


The natcmp() function lets you compare two values using the national sort ordering.
natcmp (value1, value2)

Omnis converts both values to strings before doing the comparison.


Omnis uses the same rules for comparing the strings as it does for normal strings, except
that it performs the comparison using the national sort ordering.
natcmp() returns 0 if the strings are equal, 1 if value1 > value2, and -1 if value 1 < value2.

User Interface
The Omnis preferences accessed from the IDE Tools>>Options menu line let you assign a
new language from the dropdown list in the $newlanguage property. The current language is
shown in the $language property. The language must already be defined in the localization
data file.
The new language does not apply until you quit and restart Omnis. Note that if the
localization database is shared by several users, then the new language setting affects each
of them, as soon as they restart.
An Omnis library, OmnisLOC.LBS is provided that lets you create and edit language
information. To use it:

Take a backup of the OmnisLOC.DF1; you may prefer to work on the backup copy
rather than the live copy, in which case you should make a working copy as well as a
backup copy
Open the OmnisLOC.LBS library, found in the Local folder in the main Omnis folder.
You are prompted for the location of the localization data file and a localization menu
is installed on the IDE menu bar, to the right of the Tools menu
Select Current Language to display the language in use
Select Language Records to create a new set of language information, or to edit an
existing one. This displays a dialog containing a set of tabbed panes and the standard
Omnis Insert, Edit, Find, Next and Previous buttons

You use the Next and Previous buttons to move through the records in the data file, the Find
button to locate a particular language record, and Edit to modify data already present in the
data file.
Two Insert buttons are available. Insert lets you create a brand new record, while Insert CV
lets you make a copy of an existing language record and edit that. This is particularly useful
for cases where there are only minimal differences between two language records. To use
Insert CV:
432

Localizing the Omnis Runtime

Display the language record you want to copy

Click on Insert CV

A new record is created. Remember to edit the language name as well as the specific
internal data.

When all the data is input, click on OK to store it and close the library

If you were working on a copy of the data file, move it back to the local folder

Close the OmnisLOC library

Any fields that are left blank will default to a single space. Some of the fields on the
General tab are limited in terms of which characters can be used; for example trying to
define a letter as a decimal separator is not allowed, and will generate an error message.

Setting the Locale


In the localization library (omnisloc.lbs), the sort order field is now labeled Locale. There is
a new check box below the Locale field, Use Locale For Defaulted Items. This
determines the locale used for language items that have been left empty, so that they get a
default value from the system:
1. If the Use Locale check box is checked, default values come from the locale stored in
the language record.
2. If it is not checked, default values come from the operating system default locale.

Notation
There is no requirement to manipulate localization data at runtime, so the localization
notation is minimal.
$root.$prefs.$language
a read-only property which returns the name of the language Omnis is currently using
$root.$prefs.$newlanguage
a property that lets you assign the name of the new language, that is, the language
Omnis will use when it restarts
$hascurrlangnationalsortorder
a property of a data file, for example
$root.$datas.DataFile.$hascurrlangnationalsortorder
if true the sort order matches that for the current language, and false otherwise
Every data file stores its national sort order. When you create a new data file, Omnis stores
the national sort order for the current language in the data file.
433

Chapter 12Localization
$hascurrlangnationalsortorder is assignable, but you cannot set it to kFalse only kTrue.
When set to kTrue Omnis drops all of the indexes from the data file, changes the sort order
to that for the current language, and rebuilds all of the indexes.

434

Localizing the Omnis Runtime

Chapter 13Version
Control
This chapter describes how you can use the Omnis Version Control System (VCS) to
control Omnis application development in a team environment. In such an environment,
with several people working on the same application at the same time, perhaps in different
locations, you need to ensure that only one person can change a particular component at a
time and that any modifications are not lost or overwritten. The Omnis VCS allows you to
control the development of your Omnis applications, or any other project involving many
different files such as web or Intranet applications, and it allows you to build your
application for deployment to your customers or organization.
The Omnis VCS lets you revise Omnis library files and other application components
systematically. Apart from the Omnis libraries and classes within those libraries, you may
have your own externals, text files, web components, Html files, and so on, that are all
necessary to the running of the application. The Omnis VCS can handle all these types of
files and components.
In this chapter, the term component is used to refer to all types of files and different
components stored on disk. With regards to the Omnis VCS, a non-Omnis component is
any disk file or external component other than an Omnis class.

Pre-Studio 5 VCS Repositories


There is no change in the structure of VCS repositories from Omnis Studio version 5 to
version 6, but if you are upgrading to Omnis Studio 6 from a version prior to version 5, you
cannot use your old VCS repositories. In Omnis Studio version 5 there were a number of
significant changes to the structure of the VCS which means repositories created in
versions of Omnis Studio prior to version 5 will not work with Omnis Studio 6.
Existing VCS repositories created in versions of Omnis Studio prior to version 5 must
therefore be re-created in Omnis Studio 6 to ensure that they are in the new format. To do
this, you must do a build of your existing project (or projects) using your old version of
Omnis Studio, create a new VCS repository in Omnis Studio 6, and check in your
project(s) and components into the new Studio 6 repository. You will also need to setup all
user accounts and preferences in the new repository.

435

Chapter 13Version Control

Overview
To place Omnis libraries under version control you check them into the Omnis VCS from
the Libraries tree in the Studio Browser, or for non-Omnis components from the File
Browser in the VCS itself. All the components you check into the VCS are kept in a project.
The VCS stores each project in its own repository database, which can be a remote server
database or an Omnis data file.
The Omnis VCS provides all the functionality to set up, manage, and use version control,
including:
Creating a database session and VCS repository
Checking in Omnis libraries and other non-Omnis components
Creating a project
Managing and supervising users
Building projects and libraries for distribution
Managing projects and granting user privileges
Setting VCS options
The Omnis VCS is permanently available in the Studio Browser. To use the VCS click on
the VCS option in the Studio Browser. The Session Manager and the Open Session options
are shown in the Studio Browser. To use the VCS you must first create a database session to
store your project.
The VCS tree displays all your open projects and works in a very similar way to the
Libraries and SQL Browser tree. The VCS context menu lets you open and close sessions,
and perform user administration functions. When you select a project in the VCS, the
Browser shows the contents of that particular project.

436

Setting up a Project

Setting up a Project
This section is for the lead developer or manager in the development team and details how
you setup a VCS repository and create a new project containing all your application
components.
To use the VCS you need to connect to a database via a session, set up the Supervisor user,
and create a VCS repository. You can open a VCS session using the SQL Browser, but you
should use the VCS session browser for convenience.
You can create a repository on a server database, such as Oracle, Sybase, or MySQL, or in
an Omnis data file, that is, Omnis own built-in database. You can access a repository using
a native DAM for the chosen database, or you can use ODBC or JDBC. Connecting to your
server or Omnis database by creating an Omnis session is covered earlier in this manual.
Once you have connected to your database, the VCS operates in the same way, regardless of
the database and the location the repository is stored in.
To setup a new project, you need to:
Define a new database session, and create a new repository
Sign in as Supervisor, then create and define users
Check in your libraries, classes and other components (the check in process creates a
new project for you) and assign access privileges to components for individual users
You also need to tell the members of your development team their usernames and
passwords, and provide them access to the VCS repository

Sybase Repositories
If you are using Sybase for your VCS repository, you must make sure the transaction log
has enough capacity to handle your transactions. See the Sybase documentation for details
on the transaction log. You can use the command
dbcc checktable (syslogs)

while you are running the VCS against your repository to check the status of the transaction
log. You must also set the option select into/bulkcopy to false with the following remote
procedure call
sp_dboption <db>, select into/bulkcopy, false

where <db> is your Sybase database name. The VCS issues an error message and aborts
logon if the target database has the select into/bulkcopy option set.

437

Chapter 13Version Control

Creating a session
To create a new VCS session, you can either use the default session, called VCS_Session,
or create a new one.
To create a VCS session

Select VCS in the Studio Browser and click on the Session Manager option

Click on the New Session option

The Modify Session dialog opens which allows you to enter the details of the new session.
To duplicate a VCS session
If you have a session that is a suitable template for a new one

Select the existing session and select Duplicate from the Sessions menu

In either case, a new session appears in the VCS Session Browser. You can now click on
your session and modify it.
To modify a VCS session

Select the session in the Browser and click the Modify Session option

or

Double-click on a session to modify it

The Modify Session dialog lets you modify the details of the selected session; it is identical
to the session definition dialog in the SQL Browser.
Note that to make a session usable with the VCS, you must select VCS from the Session
type dropdown list.
The information you need to supply depends on the database you want to use, but would
normally include hostname, username and password, plus you need to select the correct
DAM for your chosen database. You dont need a username and password for an Omnis
data file.

When you have modified the session, click on OK to close the Modify Session dialog

To open an existing VCS session

438

Select the VCS option in the Studio Browser, click on the Open Session option and
select the session from the list of VCS sessions
Enter the Username and Password to open the session

Setting up a Project

Time Settings
The Omnis VCS supports the UTC (Co-Ordinated Universal Time) standard time setting.
The VCS stores times in UTC, but displays times according to the time zone that has been
set. There is a preference to set the local time zone, which you can set on the Display tab
under the VCS Options.

Signing in to the VCS for the first time


When you create and/or open a VCS session, you must log on to your database and sign in
to the VCS as the Supervisor user. The VCS logs on to your database and checks for a
repository. When you open a VCS session for the first time, a VCS repository will not be
found, and the VCS prompts you to add certain VCS resources or tables. If you click on the
No button, the log on process is aborted. If you agree, certain VCS tables are installed so
the repository is available for use, and a user called Supervisor, with password password,
is set up automatically.
Once logged on to the repository, the Supervisor has access to an option from the VCS
context menu titled Remove Repository, this option will remove all the tables created by
the VCS.
To sign in to the VCS for the first time
When you log on to your VCS repository, the Sign in window appears. When you logon for
the first time you need to sign in as Supervisor.

Enter the user name Supervisor and the password password

Both the user name and password are case sensitive, so make sure both words are in the
correct case, otherwise you will not be able to logon.

Click on OK

To ensure a secure system, you should change the Supervisor name and password. You can
do this later, but to do it now

Select the VCS option in the Studio Browser and click on the User Admin option

The User Administration window lets you add and remove users, and initially displays only
one defined user, Supervisor. The columns in the list show details about each user, in this
case the Supervisor, including the user's name, password, phone extension, department, and
status.

Change the Supervisor user name to your name and enter a new password

Enter any more information you wish to store, and click on the Finished button

439

Chapter 13Version Control


As a Supervisor, you can allow other users to have Supervisor status so they can create and
delete users as well. You will also need to set up the regular users who will check
components in and out, and set up preferences.

Adding and Removing Users


User administration involves managing the users of a project and assigning them privileges
for the components in the project. Before developers can start using the project, you need to
add each one as a project user and grant the right privileges for the components they need to
change.
Once you sign into the project as Supervisor, you can add, alter and remove users of the
project. The User Administration window displays a list of existing users. The Supervisor
can add any number of additional users and assign the following privileges which determine
the extent to which a user can access components:
Observer
can see components only, therefore user cannot check components out or in
Participant
user can check components out and in, but cannot perform user admin
Supervisor
can do everything, including adding or deleting users and changing user details, and
checking components out and in
Only a Supervisor can see a users password. Only the first Supervisor user can grant
Supervisor status to other users.
To add a new user

440

Click on the User Admin option and click on the Add User button, or you can rightclick on the list of users and select Add User
Add the new user information, including the username and password; you can add the
phone extension number and department name for the user as well

Change the type of user as appropriate; a new user is set to Participant by default

Click on the Finished button and you are prompted to Save the Changes

Checking in Components
To change an existing users definition

Select the user in the list and change the user details,

Click on the Finished button and you are prompted to Save the Changes

Do not change the status of the Supervisor user, particularly if you have only one user with
Supervisor status. If you change the status of the Supervisor user you will no longer be able
to manage the project and its users.
To delete a user

Select the user in the list and click on the Delete button

Click on the Finished button and you are prompted to Save the Changes

Checking in Components
The final step in setting up your project is to check the components in your application into
the VCS. You can check in complete Omnis libraries to include all the classes in those
libraries, you can check in individual classes from any number of different libraries, and you
can check in a whole folder hierarchy containing all the necessary files for your application.
Once you have checked all the components in, other users can build a local working version
of your library or project using the Build Project option.

Creating a New Project


When you check in your library classes and other components for the first time a new
project is created for you automatically. Using this check-in method creates a new project
with the same name as your library. Alternatively, you can create a new project using the
New Project option in the VCS window, although this is not necessary if you start by
checking components into the VCS.

Checking in Omnis Libraries and Classes


All developers working on a project should have access to all the Omnis classes in your
library. Therefore, you should check in all the necessary classes in your library, including
any system tables, superclasses, and task classes. The system tables contain information
about the fonts, display formats, and so on, used in your library. In particular if the objects
in your library use field styles you should remember to check in the #STYLES system table.
You can use the Class Filter option (press F7/Cmnd-7) in the Studio Browser to make sure
all the classes in your library are displayed. In future, if you change the system tables in
your local library you must remember to check them back into the VCS along with any
other classes you may have changed. You should not check in the #DEBUG system table
class that may appear in Omnis; this exists temporarily for internal use only.
441

Chapter 13Version Control


To check an Omnis library or individual classes into the VCS

Open the Studio Browser and your library containing the Omnis classes you want to
check in to the VCS

If you want to check in individual Omnis classes

Display the classes in your library, and drag and drop your library or selected classes
onto the VCS node in the Studio Browser tree (or if you have created a project
manually, you can drop the components on the project name)

or you can

Select your library or individual classes in the Studio Browser, right-click on the
object(s) and select the Check-in option from the context menu

Whichever method you choose, the Check in components dialog appears. This dialog lets
you set the check in options for the selected components. If you check in a library all the
classes in the library are checked in automatically.

Select the Add new component radio button, and type Initial check in or something
similar in the Check In Notes field

Version Numbers
The version string for each component is currently set to 1. You can enter a special
version in the Version field if you want to use a different numbering scheme, although this
is not recommended. All the components in the VCS have both a version and a revision
number, each of which is an integer value. The version indicates the major revision or
release of a component and typically applies to all the classes in the library, so its
effectively the version of the library. The revision number indicates a relatively minor
change to the component. When you first check in a component, you can assign it a version;
the VCS automatically sets this to 1 and the revision number to 0. Each time you check in a
component, the VCS assigns a new revision, but the version doesnt change unless you
change it explicitly in the check in dialog.

Click on the Continue button to start checking in

A progress bar shows the number of components added. When all the components are
checked in, the project appears in the VCS tree, with the same name as your library.

442

Checking in Components

Checking in non-Omnis Components


You can use the Omnis VCS to control most other types of non-Omnis components such as
external components (DLLs or plug-ins), documents, Web pages, PDF files, Omnis data
files, and so on. In fact you can use the Omnis VCS to manage any type of project
containing any number of files, including ones that dont contain Omnis libraries or classes.

File Browser
To check in non-Omnis components you use the File Browser available within the VCS
itself.
Important Note: You can check Omnis library files into the VCS using the File Browser,
but this is only appropriate if you want to manage the library as a discreet disk file.
However, if you want to access all the classes in the Omnis library, you should check the
library into the VCS as separate classes, as described in the previous section, and not using
the File Browser.
To check non-Omnis components into the VCS

Select your project under the VCS node in the Studio Browser (not in the right-hand
pane)
Click on the File Browser option
Locate the files or folder you want to check into the VCS using the Select Files/Folder
button

From thereon, the check in process for non-Omnis components is exactly the same as for
Omnis classes, that is, the Check in components dialog appears which lets you set the check
in options for the selected components.
If you check in a folder, all the files and all subfolders and files within that folder are
checked into the VCS. In this case, you could, for example, check in a complete folder
structure containing your own Help system.

Viewing the Contents of a Project


To see the contents of a project

Select the project name in the VCS tree, or double-click on the project icon in the VCS
Browser

You may find the Details view most useful when viewing the components in a project, since
that view shows information such as the version, the status, which user has checked each
component in or out, and so on. You can change the view using the View menu on the main
Studio Browser menubar. In addition, you can sort the contents of your project by clicking
on one of the column headers in the VCS Browser.
443

Chapter 13Version Control

Project Folders
You can create folder classes in an Omnis library to allow you to store and organize the
classes within the library. When you check a library into the Omnis VCS these folder
classes are copied into the VCS project. It is also possible to create a folder class directly
within a VCS project via the hyperlink option New Folder available at the VCS project
level. This will allow you to organize the classes in your VCS project, but will also allow
you to organize non-Omnis objects such as external components.
Depending on how a project folder is created and what it contains, it can have one of three
possible states:
a normal folder is one that is generated withing an Omnis library and contains only
Omnis classes
an external folder is one that is generated from within the VCS
a hybrid folder is one that contains both Omnis classes and non-Omnis Objects

Building a Project
When you build a project, normal folders will be built in the destination library as at
present. External folders will be built into the file system using the folder name as a
directory appended to the build path with any non-Omnis Objects built there. A hybrid
folder will build a folder class in the Omnis library along with any Omnis classes inside it as
well as building to the file system.

Moving classes & components between folders:


If you move a non-Omnis Object to a folder class that was previously generated from an
Omnis library (a normal folder), that folder will become a hybrid folder. The same thing
will happen when you move an Omnis class to an external folder.
Note: Once a folder has become a hybrid, it will remain one: Therefore empty folder
classes may be generated when building a project even if you have deleted all classes from
the folder.

Hiding and Showing Project Folders


It is now possible to hide the folders within a VCS project thereby giving you a flat view of
all the components in your project. This may be useful when you want to quickly locate a
class rather than navigating the entire folder structure in your project.
To hide or show the folders in your project, click on the Hide / Show folders hyperlink
option in the VCS Browser.

444

Checking in Components

Assigning Component Privileges


When you have checked in all the necessary components into your project, you need to
assign access privileges to each component for each user.
To grant component privileges

Select the set of components for which you want to grant the privileges
Click on the Privileges option or right-click on the component(s) and select the
Privileges option from the context menu

The Assign Component Privileges window lets you assign privileges for specific
components to particular users.

Select one or more users and one or more components


Select one of the levels of privilege, either Read/Write, Read Only or Info Only, and
click the Set button to grant the privileges

Alternatively, you can check the Assign privileges when checking in for the first time
option under the Check In tab on the VCS Options dialog to ensure that all users are granted
access to all components in your project automatically when you first check in the
components.
For more details about assigning privileges to components see the Managing Components
section.

445

Chapter 13Version Control

Using the VCS


This section is for developers who wish to check out components from the VCS and start
working on their application. Lead developers or managers (Supervisors) wishing to setup a
VCS repository and create a new project should read the beginning of this chapter.
Once the Supervisor has created a project, set up the users, checked in classes and granted
access to components, users or developers can start using the VCS. Assuming you have
Participant user status, you can:
Sign in to the VCS
Check out one or more components that you need to work on
Check those components back into the VCS once you have finished with them

Signing in to the VCS


To sign in to the VCS as a user

Click on the VCS option in the Studio Browser

Click on the Open Session option and select the appropriate project in the list

Enter your user name and password

If you dont have a valid user name and password, you can sign in as a temporary user by
checking the Observer check box. An observer can view information about the components
stored in a project, but cannot check components in or out, or perform any other VCS tasks.
Alternatively, you can check the Create User check box to create a new user and password,
which signs you in with Participant status. The Supervisor can change your user status at a
later stage if required.

Click on OK to sign in to the VCS

Checking Out or Copying Out Components


When you check out a component into a local library, it becomes locked in the VCS,
preventing other users from checking it out. A locked component is shown in the VCS with
a lock icon. Alternatively, if you copy out a component it is not locked in the VCS and other
users can check it out if they wish. When copying out a component you can change it in
your local library, but you cannot check it back in to the VCS. In practice, copying out is a
convenient way of viewing components locally without locking them in the VCS.
You can check out or copy out multiple components at the same time, but they must all be
Omnis classes or all non-Omnis components during a single check out process. Components
may have the same or different target libraries or folders.
446

Using the VCS


To Check out or Copy out components

Display the components in your project by double-clicking on the project in the VCS
Browser, or selecting the project name in the VCS tree
Select the components in the VCS Browser that you want to check out or copy out
Select the Check Out option, or right-click on the component(s) and select the Check
out option in the context menu

or for Omnis classes only

Drag the classes from your VCS project and drop them on the appropriate library in the
Libraries node in the Studio Browser
In the Check out dialog, select either Check Out or Copy Out and whether the
component should overwrite an existing one or prompt for a new name (you can change
the default for both these options in the VCS Options)
You can add a description for the checking or copying out process

You can add a separate note for each component by clicking the Expand Notes button.

Click on Continue

If the VCS cannot locate the original library for an Omnis class, it will prompt you to select
a target library. You should select a library, or skip this component. The VCS may prompt
you to locate a library for further classes. For non-Omnis components the VCS prompts you
for a destination folder.
If you check out an Omnis class that has a superclass or belongs to a design task, read-only
copies of the superclass(es) and design task are copied out, assuming the Automatically
copy out related components preference is enabled in the VCS options.
In the Libraries tree, Omnis classes are shown as checked out with a lock icon.

Checked Out Classes


The Checked Out Classes option in the main VCS browser opens a list showing all the
classes that are checked out by the current user, or for the Supervisor user, the window
shows a list of checked out classes for all users.

Updating Properties
When checking out a class, you can update the destination library properties with the
properties that are held in the VCS for that project. This is especially useful for situations in
which there are multiple developers working on the same project. You can enable this
feature by checking Update the destination library with preferences from the VCS option
on the Check Out tab of the VCS Options.
447

Chapter 13Version Control

Superclass and Design Task Names


You can maintain the superclass or design task library name for checked out classes by
enabling Maintain superclass / design task library name option on the Check Out tab of the
VCS Options. In this case, the superclass (or design task) library name is not removed from
checked out classes. This is necessary when the superclass exists in a separate library and
there is a class with the same name as the superclass in the current library.

Checking in or Unlocking Components


When you have finished making changes to a class or component in your local library, you
need to check it back into the VCS. This unlocks the component in the current VCS
repository and allows other users to check it out and make changes or propagate your
changes into their local libraries.
Checking in a component releases its lock and makes it available to other users for checking
out. The VCS stores the changes in its repository and updates the revision number. You can
see the current version and revision by clicking on a component and clicking the
Information option when the component is selected.
You can also unlock a component without checking in a new version to make it available
for other users. You could do this if you decide you dont want to make any changes to a
component after all, or if someone else needs to make immediate changes to a component
that you have checked out and is currently locked. In the latter case, you can unlock the
component, and check it out again when the other user has made their changes. You can
unlock selected components by clicking the Unlock option when the component is selected.
To check in Omnis classes

Select the component(s) in your local library in the Studio Browser

Drag the selected component(s) on to the appropriate project in the VCS Browser

or

Right-click on the component(s) and select the Check In option from the context menu

To check in non-Omnis components

Assuming your project is selected in the VCS, click on the File Browser option

Locate the folder containing the files your want to check into the VCS

For all types of component, the Check in window appears which lets you set the check in
choices for the selected components, as already described in the Setting up a Project
section.

448

Using the VCS


You can select one of the following check in modes
Add new revision
adds the component by incrementing the revision number by one, unlocks the
component, and updates the check in date, time and other status information
Add new component
adds the component as a new one, setting the version to 1 and revision to zero, by
default
The After Check in option lets you decide whether to
Keep checked out
adds the component to the VCS and locks it; in effect, this allows you to backup your
components but keeps the component(s) checked out and available for you to make
further changes
Delete local copy
adds the component to the VCS and deletes the local copy
You can enter a new version in the Version field or accept the default, and regardless of the
check in mode, the VCS sets the version to that number.

Showing Checked Out Classes


You can view only the checked-out classes in a VCS project. To show the Checked Out
classes in your project, click on the Show Checked Out hyperlink option in the VCS
Browser. To show all classes click on the Show All Classes option.
This option may be useful when you want to quickly identify all the classes that are checked
out from a project, and you can combine this option with the ability to hide/show project
folders, as above, to view all checked out classes within folders.
When only the Checked Out classes are showing you can select one or more classes, rightclick on them and select the Check-in option. You can also run the Class Comparison tool
from the same context menu. If there are classes that belong to more than one library, or if a
library is not open, these options are disabled.

449

Chapter 13Version Control

Building Projects
The Omnis VCS lets you build a project on your local workstation, or any other destination,
from the components stored in the VCS repository. You can do this at any time using the
Build options in the VCS. You can also build projects at a specific time and date using the
Scheduled Build option, which is described in the next section in this chapter.
Building any type of project from the VCS guarantees that all the components in your local
copy are up-to-date. In the context of Omnis application design, building a project means
creating a library containing up-to-date classes for you to work on or test. If your Omnis
application contains multiple libraries, doing a build from the VCS guarantees that your
whole application is up-to-date. You can also build a project containing non-Omnis
components and reproduce the original folder hierarchy required in your application. Using
the revision labeling features, you can build previous versions of a library or project for
comparison, troubleshooting, or debugging.
When you build a project that contains classes from more than one library, the VCS copies
all the components to a single library by default. However by setting the Build options you
can build classes to separate libraries, thus maintaining your original library structure.
You can update a local copy of a library in the Studio Browser using the Update from
VCS option. This is appropriate for updating single libraries, but is not appropriate for
building a complete project. The Update from VCS option is described later in this chapter.
To build a project with multiple libraries

Select the VCS in the Studio Browser and click the Options option
Click on the Build tab and check the Maintain Project Structure option; this will
ensure your project builds to multiple libraries where applicable

To build a project
Whether or not you are building to one or more libraries

Select your project in the VCS Browser


Click on the Build Project option, or right-click on the project and select the Build
Project option from the context menu

The Build Manager lets you configure the project build in detail. It contains one line only if
you have chosen to build a project containing Omnis classes into one library, with the
project name as the library name. If you have set the preference to maintain your library
structure, the Build Manager lists each separate library in the project. If your project
contains non-Omnis components you can enter the name and path of the target folder.

450

Select the library or project and specify the Build options as follows

Using the VCS


You can name the output library using the Label and Build As options:
Label
lets you select the version of the library that you want to build; see the Labels section
below
Build As
lets you select the name of the output library
You can set the following options for the output library:
Use Locked and Unlocked folders
if set, you can use locked folders, otherwise if the option is unchecked, all folders and
libraries are unlocked
Locked and Unlocked
if set, creates a locked and unlocked version of your library
Locked
if set, the build process creates a locked version of your library preventing other users
from seeing or changing the contents of the library; checking the Locked check box
option locks the whole contents of a library but you can lock individual classes using
the Lock Classes window.
To lock individual classes, uncheck the Locked option, right-click the project in the
Build window, select the Lock Classes option, and select the classes you want to lock in
the popup window. Note you can also lock folders, which will lock the whole contents
of the folder
Strip Comments
removes comments from your Omnis code, as well as variable & file descriptions; also
enables the class selection context menu; see the Remove Comments section below
Overwrite
if true, overwrites all the components in the target library or folder, that is, the VCS
removes all the classes in the target library and completely rebuilds the library.
Otherwise if the option is unchecked, the VCS updates only the components that are
different from the current library or project. This is useful for quickly bringing an
existing library up-to-date with the current checked-in classes in the VCS
Lower case
ensures the library name is in lower case

Type the path for your library or project in the Build into field or use the Browse
button to select a folder or create a new one
When you have set the options for your project, click on the Build button

451

Chapter 13Version Control


The VCS opens the Build Results dialog showing the progress and status of the build. The
VCS creates a log file for the build and displays it at the bottom of the build window.

Removing Comments
When you create a build from the VCS, you can remove the comments from the code in
your libraries by checking the Strip Comments check box. If the option is set, all
comments within methods are removed, as well as all variable definitions, and descriptions
for file, query, and schema classes. This will make library files smaller, which may be better
for deployment.
You can select classes that you want to retain their comments when you build a project. To
do this, right-click on the list of projects in the Build Window, select the Do Not Strip
Comments option, and select the classes in which you want the keep comments.
Under the Build tab in the VCS Options window, there are four checkboxes that, if checked,
will ensure that comments in variables, file classes, query classes and schema classes are
retained.

Checked out Classes


When you create a build from your Omnis VCS repository, the project may contain classes
or objects that are checked out of the current repository. If you proceed with the build, your
project may not contain the most up-to-date classes. In this case, you may want to look in
your project before building the project to ensure that all the classes in the project you want
to build are all checked in.
If the Warn if there are classes checked out option is set (in the VCS Options), the VCS
will warn you that the build contains classes that are checked out. In this case, a window
will open listing all the checked out classes with an option to proceed with the build or
cancel it. To build a completely up-to-date copy of a library, you should ensure that all
classes are checked into the VCS before proceeding with a build.

System Tables
When you build a library, the VCS includes the system tables by default, assuming you have
copied them to your project. The system tables contain library-specific settings such as
fonts, input masks, field styles, and in the case of #ICONS the icons in your library, so they
are important in maintaining the correct look-and-feel and behavior in your application.
Remember that when you check in a version of the library, the VCS does not automatically
put the system tables into the library; you must specifically show and select them in the
Studio Browser just as you do the other classes in your library.

452

Using the VCS

Scheduled Builds
The Omnis VCS allows you to build projects at a specific time and date, which for large
development teams may be useful if you need to build a library out of office hours. You can
set up a Scheduled Build from the Scheduled Build option in the main Omnis VCS
Browser. When you select this link, the Build Manager will open containing a new button
called Schedule, which opens the Schedule Build Process window.
The Schedule Build window allows you to control the frequency of the builds and set the
time that you want the build to run. The following options are available:
Never
no scheduled builds occur, but you can still build a project manually
Daily
the build will occur every day at a specified time
Weekly
you can specify which day(s) of the week the build should occur during the week; you
can also set the time
Monthly
the build will occur once a month, on the specified day of the month; you can also set
the time
The best time to schedule the build is when there is no one else logged on to the VCS. You
must ensure that Omnis Studio is running at the time of the build and that you are logged on
to the correct VCS repository. If you do not have Studio open at the time of the build
schedule, when you next log on during that day, the VCS will prompt you that you have
missed the scheduled build and ask if you want to run it then. For example, if you have the
build set to run at 7am on a Monday, but do not start Omnis until 8am, Omnis will remind
you about the build that you missed.
You should use the Build Manager window to define the projects you want to build and
how you want them to be built using the normal options that are available. When you click
the Finish button these preferences will be saved and the timer started according to the
schedule defined.

Labels
You can choose to label the build either at the time you schedule the build or when the build
runs. Note that if you select Label at Build and there is already a label with that name, the
VCS will redefine the label with the current state of the classes. This may or may not be
what you require, so caution should be exercised, particularly if you are setting the build to
run every day and therefore you may lose the ability to rebuild to a specific point in the
project development at a later point in time. If you select Label Now, the VCS will prompt
you if there is already a label defined and give you the chance to confirm that you want the
label redefined.

453

Chapter 13Version Control

Locked or unlocked
You can specify whether the VCS builds a locked or unlocked version of your library (or
both) using the Library Status dropdown list in the Build window.

Build notes
If you have selected a path to save them into, the build notes will be saved to a file prefixed
AutomaticBuildNotes_ within that path. By default the path is the BuildFolder within the
main Studio folder.

Project Branching
The Omnis VCS allows you to create branches within the current project, based on the
contents of your original project. You are then able to make changes or additions to the
branches in your project, thereby in effect making different versions of the same
project/application. The ability to create branches may be of real benefit to developers who
have different customers with differing or urgent requirements, outside of your normal
product release cycle. In this case a branch can be created and tailored to an individual
customer, perhaps to provide them with an urgent patch.
Project branching allows you to create and maintain multiple development paths alongside
each other within a single project. Each branch is based on the original project branch, but
is independent of each other.
Note: please note there is no function at present to merge different branches, so you should
think very carefully before creating multiple branches in a project and allowing separate
independent development paths to be created.

Creating a Branch
You can create a branch by clicking the Make Branch hyperlink in the Omnis VCS
browser window. By default the new branch will be called _Branch_1, but you can rename
it either at this point or after creation using the Branch Manager tool. When you create a
new branch, you can set it to be the default branch, although youll probably want to keep
the original branch as the default: see below.
The VCS creates the new branch and places the contents of your original project in another
branch called _Trunk. At this point the new branch will be identical to the contents of
_Trunk. Any assigned user privileges in the original project are carried over to the new
branch. The VCS displays the two new branches or nodes underneath the original project
name.
There is no difference between the _Trunk and any other branch, that is, all branches have
the same properties, so the Trunk simply identifies the contents of your original project.
You can create as many branches as you wish, attached to the main Trunk, but you cannot
create a sub-branch, that is, a branch of a branch.

454

Using the VCS

The Trunk and Default Branch


When you create the first branch and you dont set it to be default branch, the original
development path in your project is named _Trunk and it becomes the default branch. A
check mark icon indicates the default branch. The default branch can be changed at any
time by right-clicking on a branch, but in most cases the original _Trunk can remain the
default.
The following functions work only for the default branch:
Build Updated Libraries
Update from VCS
Auto Checkin

Branch Options
There are two new options that allow you to manage the Checkin/Out process for projects
that contain branches. See the VCS Options section in this chapter.

Building Projects with Branches


When a project is branched, the Build option is only available at a branch level except for
Scheduled Build, which will allow you to set the branch you wish to build at the specified
time.

Managing Branches
The Manage Branches window lists all the branches defined for a project and allows you to
label or delete branches. You can open the window from the Manage Branches hyperlink in
the VCS browser.
Deleting a Branch
You can delete any branch apart from the _Trunk. To delete a branch you can use the
Manage Branches window or Delete Branch hyperlink. If all branches are deleted from a
project, the _Trunk is also removed, and all classes belonging to the _Trunk are reassigned
to the original project.

An Example Scenario
Consider the following scenario: An Omnis developer releases a version of their application
and begins work on the next version, checking changes into the VCS as the project
progresses. Then a bug is identified in the released version which requires an urgent fix,
perhaps for a particular customer who cannot wait until the next release to receive the fix. In
this case, the developer could add a branch to the project, make the fix in the new branch
and release an interim fix to satisfy the customer.
After the interim release is made, further work may be carried out on the main product
branch (probably the Trunk/Default branch), which will then be released at some time in the
future. In this case, the main product will not include the urgent fix, since it was made to the

455

Chapter 13Version Control


other branch in the project. If the developer wants to include the urgent fix in the main
product, they will have to add the fix to the main branch (or indeed multiple branches) to
ensure that the fix is carried forward. Apart from this possible need to reconcile changes
made to different branches, the ability to create branches may be of real benefit to
developers who have different customers with differing or urgent requirements, outside of
their normal product release cycle.

Labels
In long-term projects, the components in your project may undergo many revisions. The
VCS tracks these revisions using labels. You can reproduce a particular version of a library
using the appropriate label. A label is a string of up to fifty characters that you can assign to
a project and each of its components. When a project is complete and you want to release it,
you can assign a release name by labeling the project. You can see the label for a project or
individual component in its Information window.
To label a project

Select the project in the VCS Browser


Click on the Label Project option, or right-click on the project and select the Label
Project option from the context menu
Type in the label and click OK

Once a project has been labeled, the last label assigned is shown in the VCS Project
Browser if the browser is in Details view.
When you build a project, you can use labels to select either the latest version of all the
components, or an older version. You can also check out a specific revision of a component
using its label. See the description of the Check Out process in the section on Managing
Components below.
If you delete a component that has a label, it remains in the VCS. If you build a project
using that label, the VCS finds and includes the component in the build even though you
have deleted it from later revisions of the project. The VCS does not include the component
in any builds or labels that occur after you delete the component. For example, if you label
a project and its components on Monday, delete a component from it on Tuesday, and do a
build on Wednesday using Mondays label your library will include the component.
However if you do a build on Wednesday using the most recent project label, your library
will not include the component you deleted on Tuesday.

Finding Classes
The Find Class option in the VCS Browser lets you search for a class within the current
VCS repository. You can search for a class within one or more projects. A list of matching

456

Using the VCS


classes is displayed, and you can double-click a class to display that class in the appropriate
project.

Updating local libraries from the VCS


The Update from VCS option, available in the main Studio Browser, allows you to bring a
local library up to date with the latest version of the library in the current VCS repository. If
you have large libraries and multiple developers you may find this a quick way of ensuring
that a local copy of a library has all the changes made by other developers.
To use this feature, select a library in the Studio Browser and click the Update from VCS
option. Providing that you have a VCS session open and that there is a project in the VCS
repository that matches the name of the current local library, this option will bring up the
checkout window (in Copy Out mode only) listing all the classes that have a newer class
modified date in the VCS than your copy of the library. It will also list all classes that have
been added to the repository that do not exist in your local library. If there are classes which
you do not want to update, you can uncheck them in the checkout window.

Read-only classes
When you try to modify a class in a library built from the VCS, it is only possible to edit the
class when the class is checked out. If it is not possible to edit the class, the class is
considered to be read-only.
1.

If a library has a non-empty VCS build date, then all class editors behave in a read-only
fashion, when $showascheckedout is kFalse for the class being edited.

2.

You can disable this behavior using the $alloweditifnotcheckedout Omnis preference
($root.$prefs) which is set to kFalse by default. Set it to kTrue, to disable this behavior.

3.

When this behavior is enabled, new classes in a library with a non-empty VCS build
date (created in any way), are automatically marked as checked out.

4.

Replace will not work against a read-only class, an error is written to the find and
replace log.

Note that this does not affect the notation (although the notation inspector will not allow
changes to a read-only class).

457

Chapter 13Version Control

Managing Components
The VCS has an extensive array of component management functions, including
Granting user privileges for components
Associating a component with more than one project
Managing revisions of components
Deleting and renaming components

Granting User Privileges for Components


If you are the first user to put a component under version control, you are the owner of that
component. To allow other developers access to a component, you must grant them
privileges to it. Without the right privileges, other developers can only view and get
information about a component as Observers. Supervisors have all privileges at all times.
To grant component privileges

Display the components in your project by double-clicking on the project in the VCS
Browser
Select the set of components for which you want to grant the privileges
Click on the Privileges option or right-click on the component(s) and select the
Privileges option from the context menu

The Assign Component Privileges window lets you assign privileges for specific
components to particular users. You can choose one of the following levels of privilege
Read/Write
the user may check in, check out, copy out, get information on and build libraries with
components
Read Only
the user may get information on, build libraries with, and copy out a component into a
local library, but cannot check out the component nor check it back in with changes
Info Only
the user may get information only about a component

Select one or more users and one or more components

Select one of the levels of privilege and click the Set button to grant the privileges

Assigning the Info Only privilege also revokes existing privileges from a user. Info Only is
the default privilege that any user has for a component. The owner of the component must
458

Managing Components
grant the user, including Supervisors, the Read Only or Read/Write privileges necessary for
building libraries or changing the component.
By default, the owner of a component starts with Read/Write privileges for that component,
and you must have Read/Write privileges to grant privileges for it to other users.
If you select components for which you dont have Read/Write privileges, the VCS disables
the radio buttons and Set button. If you select components for some of which you have
Read/Write privileges, you can use the radio buttons. The VCS does not however, grant the
privileges to the user(s) on those components for which you do not have Read/Write
privilege.

Sharing Components between Projects


You may decide to use a single component in many projects, such as a custom logon
window, or a generic search component. The VCS can associate or link a component with
libraries in different projects, storing the component only once, but building it into different
libraries when required. You need only revise the component in one place, rebuild the
projects, and the VCS propagates the changes to all the libraries that contain the component.
You must have Supervisor access or be the owner of a component to associate or link it with
another project or library.
To associate a component with a project

Open the project containing the component, and select the component
Click on the Link option, or right-click on the component and select the Link option
from the context menu

The Link option displays a window showing all your open projects (the link window will
not open if there are no other open projects, or if the component is already linked to all
other open projects).

Select the project with which you want to link the component, or you can open a
project in the list and select a particular library
Click OK to link the component

If the Maintain Project Structure build option is not checked, the component is associated
with the single library together with all the other components. Otherwise if the build option
is enabled, the component is associated with a library of the same name as the one
containing it. If such a library does not exist, it is created automatically.
To delete a linked component in a specific project

Open the project containing the linked component

459

Chapter 13Version Control

Select the component, and click on the Delete option, or right-click on the component
and select the Delete option from the context menu

If the component has a label, it becomes disassociated and a small trash can icon is shown.
If you build a project using a label, the component is still available for the build, even
though the library or project in question may no longer associate with the component.

Managing Revisions
When you first check in a component, the VCS creates the component in its repository and
sets the version to 1 and the revision to zero. Each time you check in a new revision of the
component, the VCS stores the new component and increments its revision number. The
sequence of changes to a component is stored in its revision history.
To see the revision history for a component

Select the component in the VCS


Click on the Revision History option, or right-click on the component and select the
Revision History option from the context menu

The Revision History window tells you


the version string and revision number
the user who modified the component
the component name
and change notes, if any
The revisions for a component are listed in chronological order with the most recent
revision at the top. You can delete old or newer revisions of a component.
If you have Read/Write or Read Only privileges for the component, you can copy out the
latest revision of the component from the Revision History window by clicking on the Copy
Out Revision button. A list of currently open libraries appears, so you can choose which one
to copy the component into. Select a library and click on Select.
If a component already exists in the library with the same name as the copy, the VCS
prompts for a new name. Keeping the old name overwrites the existing component; entering
a new one renames the copy.

460

Managing Components

Method Inspector
The Method Inspector lets you examine the methods in a class without having to Check Out
or Copy Out a class or build the library. This may be useful if you want to quickly check
what methods are contained in a class or what code is contained in a particular method
within a class.
To open the Method Inspector, you can select the class and choose the Method Inspector
hyperlink option in the VCS Browser, or Right-click on the class and select the option from
the context menu.
On the first tab of the Method Inspector window, there is a list of all the methods within the
class. If the class has a superclass, the superclass methods are also shown. They are
displayed in blue to differentiate them as inherited methods.
If the selected class is a window, report, remote form, menu or toolbar, there is another
checkbox displayed at the bottom of the list to allow you view field methods. By default this
option is not selected except for menu and toolbar classes.
Further properties of the method are shown in this tab: description, execute on client and
web service method. There is also a context menu option to allow you to view the path to
the method within the class this is of most use if you are looking at field methods as you
can see the exact path to the method.
If you double-click a method, the code for the method is displayed on the second tab.
Should the method be inherited, there is a context menu option to allow you to view the
superclass code.

Orphan Components
It is possible for a component that has a parent folder to lose its parent folder; in this case,
the component is regarded as an orphan component. A component can lose its parent
folder either because the parent folder itself no longer exists, or the id of the parent folder
has changed and the component is not aware of the change. The id of the parent folder for a
component is stored in its $parentfolder property.
The Find Orphans option in the VCS will look for components where their $parentfolder
id does not exist and place these components in the Orphans folder. You can move the
component(s) back to their respective folders or recreate the appropriate folder. In most
cases, the option will return no orphan components.

461

Chapter 13Version Control

Component Services
The Component context menu gives you information about a component, and lets you
rename, delete, or unlock a component. To open the context menu you must right-click on
the component.
To get Info about a component, or rename, delete, or unlock one

Right-click on the component in the VCS and select the appropriate menu option

or assuming the component is selected, you can

Click on the Info, Delete, or Unlock option in the list of options in the VCS Browser

Get Information
This window displays the information about the component, including the labels, the
revision state, the check out history, and links.

Deleting Components
To delete a component, you must own the component and it must be checked in. The Delete
option checks whether the component belongs to more than one library and whether any
labels apply to it. If not, the VCS prompts for confirmation that you want to delete the
component. If it does belong to more than one library, the VCS displays a list of associated
libraries, letting you choose the ones from which to remove the component.

Unlocking Components
You can unlock a locked component by clicking on it and selecting the
Component>>Unlock menu option. A warning message advises you that having done this,
you will not be able to check in a previously checked out version of the component.

Renaming Components
To rename a component, you must own the component and it must be checked in. You can
rename any component in the VCS, but renaming Omnis classes requires some additional
care because of the potential dependencies of some classes on the class you want to rename.
That is, before you rename a class in the VCS you must change all references to it in any
other classes that refer to the class. You do this by checking out all the relevant classes to
the IDE Browser and using the Omnis Find and Replace tool.

462

Managing Components
To rename a class

Check out the class and any other classes that contain methods which refer to the
component
Change the name of the component in the Studio Browser, and answer Yes when you
are prompted for whether or not you want to use Find and Replace; this renames the
component and changes all references to it in any other components
Check in all the components except for the renamed one
Select the component in the VCS, and click on the Unlock menu option to release its
lock

Click on the component again when the VCS has refreshed

Click on the component to rename it

Comparing Classes
The Compare Classes option in the VCS lets you compare all the classes in two different
VCS projects, or it lets you compare individual classes in different projects. It also lets you
compare different revisions of the same class. (The Compare Classes tool is also available
in the Studio Browser and allows you to compare classes in libraries not checked into the
VCS.) The Compare Classes tool compares the properties and methods of the specified
classes and highlights any differences. Specifically, the comparison tool will compare each
line in a method of one class with the corresponding lines in a method of the other class and
will highlight even the smallest change or difference between the two classes or revisions.
To use the Compare Classes tool

Select a project or component and click on the Compare Classes option in the VCS
Browser

The Compare Classes tool is also available in the Revision History window to allow you to
compare revisions of the same class.
The Compare Classes window lets you load two different versions of the same VCS project
or library: you should load the older project or library into the Library/Project A list (on the
left) and the newer version into the Library/Project B list (on the right). The context menu
on the Compare Classes window (Right-click to open it) lets you switch libraries from List
A to List B.
You can compare all the classes in a VCS project or library that have a modified $classdata,
which avoids comparing classes that have not changed. The Compare tool shows which
classes have a modified $classdata and by default will compare only these classes. You can

463

Chapter 13Version Control


uncheck the Only include classes where $classdata differs checkbox to compare all the
classes in a project or library.
By default, the Compare Classes tool only compares any classes that are selected in the
VCS. To compare all classes, regardless of any selections in the VCS, you can uncheck the
Only include classes pre-selected in the class browser or VCS option in the Compare
window.

VCS Options
You can set your individual preferences for the VCS using the Options option in the list of
options in the VCS Browser. You can set Display, Check out, Check in, Build, Method
Inspector, and Branches options in the VCS Options window.
To set your VCS options

Select the VCS in the Studio Browser, or select a project, and click on the Options
option

Display Options
The Display options let you specify the format of dates and times for the VCS windows and
dialogs. The default format is: D m Y H:N:S, such as 12 May 09 14:30:35.
Show linked icon
(disabled by default) enables the Linked icon for classes and components that are
linked across different projects using the Link option.

Check Out Options


The Check Out options control how components are checked out of the VCS.
Default mode is Check Out Modifiable copies
determines whether or not a component is checked out or copied out; the default is for
components to be checked out in modifiable mode.
Default replacements to overwrite existing items
determines whether or not an existing component in your target library is overwritten
when a component is checked out. The default is that components are checked out and
overwritten without warning, otherwise when the option is unchecked, you are
prompted to overwrite or rename the component.
Automatically copy out related components
relates to Omnis classes that have superclasses and design tasks. If you have a class that
is a subclass of another class, and you check out the subclass, this option ensures the
superclass is checked out. When this option is unchecked the superclass will not be
copied out; in this case, you will not see any fields and methods that are contained in
464

VCS Options
the superclass. If this option is set, read-only copies of the superclass(es) are copied
out, as well as the design task for the original classes being checked out.
Default to copy out component if already checked out
when this option is set, it forces components to be checked out even if they are already
checked out. If unchecked, the VCS will warn you that the component is already
checked out and prompt you to Copy out or cancel the operation.
Maintain superclass / design task library name
ensures that classes retain the library name as part of the superclass or design task
name. The preference is unchecked by default to ensure backward compatibility. With
the preference disabled, the library name is stripped out at checkout or build time. This
means that if, for example, you have LibraryA with a class called classA which has a
superclass LibraryB.ClassSuper and there is also a ClassSuper in LibraryA, Omnis
would switch the superclass to LibraryA.ClassSuper whenever the class is checked
out or built. You can check this option to retain the superclass name to avoid this
problem.
Update the destination library with preferences from the VCS
ensures that when checked the preferences of the destination library are updated from
those stored in the VCS.

Check In Options
The Check In options control how components are checked in to the VCS.
If Target Component Does Not Exist
controls what happens when you check in a new component. By default, the
Automatically add it to the Project option is selected and components are added to a
project automatically; otherwise if the Prompt for further instructions option is
selected the VCS asks if you want to add the component to the current VCS project.
When Component Version Number Changes
controls revision numbers for new versions of a component. By default, the Reset
revision numbers to zero option is selected and revision numbers are set to zero for
new versions; otherwise if the Continue to increment revision numbers option is
selected the VCS continues to increment revision numbers regardless of the component
version. (Version and revision numbers are described earlier in this chapter.)
Assign privileges when checking in for the first time
is useful when, as supervisor, you first set up your project. When enabled and you
check in components into the VCS for the first time, the component privileges window
is opened allowing you to set the access privileges for each component.
Disable automatic library preference changes
If enabled, this option prevents the automatic updating of library preferences from the
library containing the classes to be checked in.

465

Chapter 13Version Control


Enable version number validation
allows you to disable version number checking when checking objects into the VCS.

Build Options
The Build options control builds in the VCS.
Maintain Project Structure
controls whether or not a build retains the library structure of the components within a
project. If this option is checked, components are built into separate libraries mirroring
the original library structure, otherwise all the components in a project are built into a
single library.
Warn if there are classes currently checked out
tells you if there are any classes checked out when you attempt to build a project; if you
build a project containing checked out classes your library may not contain the most
up-to-date version of classes
Only create locked and unlocked folders when required
Selecting this option prevents the VCS from generating locked and unlocked folders in
the build path unless the Build process needs them.
Stripping Comments
During a build all comments in your Omnis code are stripped out. When checked, the
Stripping Comments options ensure that comments are retained in all Variable
definitions (in the Variable pane of the Method Editor), as well as all File, Query, and
Schema classes.

Method Inspector Options


The Method Inspector options are as follows:
Ignore File Classes
When checked, the Ignore File Classes option ensures that #??? references to file
classes are not included in the Method Inspector window; the Method Inspector is
available in the Studio class browser and allows you to inspect the methods of any
classes in the current VCS project.

Branches Options
The Branches options only affect projects that contain branches; the options are ignored for
projects without branches. The Checking in/out options on the Branches tab allow you to set
the check in/out preferences for VCS projects that contain branches.
Use Default Branches
If the Use Default Branches option is checked (the default) and the current project has
branches, the default branch is used to check out classes when using the context menu

466

Reports
in the Studio browser. If the option is unchecked, a list of available branches is
displayed to allow you to choose the branch from which to check out the class.
Ignore Branches
If the Ignore Branches option is checked (the default), the VCS automatically uses the
branch the component has been checked out from. If the component is present in more
than one branch, a window is displayed to allow you to choose the branch from which
to check out the class or component.

Reports
The VCS has a number of reports available to those with Supervisor status. You can access
them by clicking the Reports option in the VCS Browser. Users without supervisor status do
not have access to VCS reports and will find this menu option is grayed out.
To use the VCS reports

Select the VCS in the Studio Browser tree and click on the Reports option

The VCS Management Reports dialog lets you select a report. The Parameters pane and
Description field will change depending on the report you click on.

Select a report and set up its parameters

Click on the Print button to generate the report

Select the required destination, and click on OK

Branches
Where appropriate, the reports in the VCS will reflect the existence of branches in your
projects.

467

Index

Index
# variables, 67
#BFORMS, 47
#DFORMS, 47
#ERRCODE, 91
#ERRTEXT, 91
#EXTCOMPLIBS, 47
#F, 72
#FD, 56
#FT, 56
#ICONS, 47
#MARFONTS, 47, 393
#MASKS, 47
#MAWFONTS, 47
#MXRFONTS, 47, 393
#MXWFONTS, 47
#NFORMS, 47
#NULL, 60
#PASSWORDS, 47
#STYLES, 47, 441
#TFORMS, 47
#UXRFONTS, 47, 393
#UXWFONTS, 47
#WIRFONTS, 47, 393
#WIWFONTS, 47
$accumulate(), 383
$activate(), 107
$add(), 77, 144, 167
$addafter(), 167
$addbefore(), 167
$addcustomtype(), 309
$allowstransactions, 205
$allrowsfetched, 247
$alwaysprivate property, 110
$appendfile, 381
$assign(), 77
$assigncols(), 170
$assignrow(), 170
$attributes, 144
$autoactivate, 107
$autobegintran, 206, 207, 330
$average(), 169
$backendpid, 307
$batchsize, 190
$begin(), 206, 219, 299

468

$bindshort0dpassmallint, 279
$blobsize, 214
$calculated, 91
$cancel(), 309
$cancelresultset(), 279
$canclose(), 378
$cangeneratepages, 378
$cankeepopen, 378
$cclass, 74
$cdata, 74
$cdevice, 377, 384
$centuryrange, 57
$cfield, 74
$changeuser(), 296
$char38touuid, 308
$characterset(), 296
$charmap, 210
$charsperinch, 381
$charsperline, 381
$checkbreak(), 383
$cinst, 74
$class, 166
$classes, 25
$clear(), 167, 169, 198, 219, 224
$clearremotepasswords(), 278
$clib, 74
$clientflags, 295, 299
$close(), 108, 378
$close() method, 77
$cmethod, 74
$cobj, 74
$colcnt(), 421
$colcount, 166
$collectperformancedata, 134
$cols, 166
$colsinset, 246
$colsublen, 169
$colsubtype, 169
$coltext, 219
$coltype, 169
$columns(), 200, 224, 298
$commit(), 206, 219, 299
$compevents, 114
$compfuncs, 114

Reports
$componenticon, 140
$components, 113
$comprops, 114
$configdsn(), 332
$connectoption(), 296
$connectstatus(), 309
$constprefix, 113
$construct(), 59, 106, 243, 427
$controlhandler, 113
$controls, 113
$copies, 383
$copydefinition(), 167
$copyref(), 153
$count(), 169
$cparmcount, 74
$createname(), 245
$createnames(), 194, 219, 252
$crecipient, 74
$ctarget, 74
$ctask, 74
$ctask, 109
$cterrorlayer, 277, 279
$cterrornumber, 277, 279
$cterrororigin, 277, 279
$cterrorseverity, 277, 279
$currentcontents, 175, 176
$cursorsensitivity, 330
$cwind, 74
$database, 295, 299, 307
$datesecdp, 329
$datetimeformat, 290
$dbmsname, 327, 341
$dbmsversion, 327, 341
$deactivate(), 107
$defaultdatabase, 327
$defaultdate, 213
$defaultname, 44
$defaultschema, 329
$defaulttask, 105
$define(), 167
$definefromsqlclass(), 61, 62, 63, 160, 167,
236, 238, 242
$delete(), 162, 244, 249
$deleteref(), 152
$designtaskname, 66, 69
$devices, 377
$disablereportcopy, 373
$dodelete(), 245, 251
$dodeletes(), 244, 250

$doinsert(), 245, 251


$doinserts(), 179, 244, 250, 251, 252
$doupdate(), 245, 251
$doupdates(), 244, 250
$dowork(), 179, 244, 251
$drivername, 290, 327, 341
$driverodbcversion, 290, 327
$driverversion, 327, 341
$editionfile, 380
$ejectpage(), 384
$emptydateisnull, 213
$emptystringisblank, 279
$encryptpassword, 277
$endpage(), 384
$endprint(), 376, 384
$endproxy(), 258
$errorcode, 175, 176, 197
$erroronnodata, 291
$errortext, 175, 176, 197
$event(), 94
$excludefrominsert, 247
$excludefromupdate, 247
$execdirect(), 188, 224
$execute(), 187, 224
$exportbom, 416
$exportencoding, 415
$extobjects, 216
$extraquerytext, 246
$failtimeout, 277
$falsetext, 260
$fetch(), 161, 163, 188, 199, 224, 244, 248
$fetchinto(), 189, 224
$fetchtofile(), 189, 224, 407
$filter(), 178
$filterlevel, 176
$filters, 179
$first(), 144, 167
$flags, 113
$flush(), 380
$font, 393
$functionname, 113
$generatepages, 381
$getcolumnname(), 421
$getcolumnnumber(), 421
$getdatasources(), 290, 331
$getdatatypemapping(), 296, 301
$getdrivers(), 331
$getinfo(), 331
$getoption(), 333

469

Index
$getparam(), 400
$gettablelist(), 421
$gettext(), 421
$group, 170
$hascurrlangnationalsortorder, 433
$height, 388
$hideuntilcomplete, 381
$hostinfo, 295
$hostname, 185
$iconid, 377
$idelistpointsize, 12
$ident, 170, 377
$importencoding, 415
$includelines(), 178
$indexes(), 200, 224
$insert(), 161, 244, 249
$inserted(), 296
$insertnames(), 194, 219, 245, 253
$inst, 387
$inuse, 217
$isa(), 141
$isfixed, 166
$isolationlevel, 330
$isolationoptions, 330
$isopen, 377
$isprivate property, 109
$issupercomponent, 140
$istext, 382
$istextbased, 377
$itasks, 104
$iwindows, 72
$language, 432, 433
$left, 388
$libs, 72
$line, 166, 171
$linecount, 166, 176
$linemax, 166, 189
$linesperinch, 381
$linesperpage, 381
$listrefs(), 152
$loadcols(), 170
$loadcolumn(), 421
$loadexistingtablefromlist(), 421
$loadlistfromtable(), 421
$loadpagesetup, 385
$loadstringtable(), 421
$loadtablefromlist(), 421
$lobthreshold, 215
$local

470

Using with tasks, 107


$locale, 278
$logoff(), 185, 219
$logon(), 184, 219
$logontimeout, 277, 295, 307, 328, 341
$longchartoclob, 409
$makelist(), 80
$makepool(), 215
$makeschema(), 201, 219
$makesubclass(), 141
$maptable, 209
$maxbuffersize, 190
$maximum(), 169
$maxvarchar, 307
$maxvarchar2, 258, 408
$merge(), 168, 173
$minimum(), 169
$moneydps, 277
$multipleresultsets, 330
$multipletransactions, 330
$name, 113, 171, 377
$nationaltonclob, 259, 408
$nationaltonvarchar, 408
$nationaltowchar, 329, 409
$nativeerrorcode, 175, 176, 197
$nativeerrortext, 175, 176, 197
$nativewarncode, 261
$nativewarntext, 261
$new(), 183, 217
$newlanguage, 432, 433
$newref(), 59, 152
$newstatement(), 185, 208, 217, 219
$newstatementref(), 59, 219
$newstatementref()., 152
$next(), 144, 167
$nextnativeerror(), 197, 219, 224
$nodebug, 122
$nodebug property, 110
$nonull, 238
$norefresh, 93
$numericprecision, 308
$oldcontents, 175, 176
$omnistoback(), 106
$omnistofront(), 106
$open(), 76, 378
$openjobsetup(), 384
$openonce(), 77
$options, 307
$orientation, 382

Reports
$pages, 380
$pagesetupdata, 385
$paper, 382
$paperlength, 382
$paperwidth, 383
$parameterstatus(), 309
$password, 185
$pathname, 113
$ping(), 296
$plsql(), 261
$plsqlarraysize, 261
$poolsize, 217
$port, 295, 299, 307
$portdatabits, 382
$porthandshake, 382
$portname, 382
$portparity, 382
$portspeed, 382
$portstopbits, 382
$posdelete(), 261
$poshorzpage, 388
$posmode, 387
$possectident, 388
$posupdate(), 261
$posvertpage, 388
$prepare(), 186, 224
$prepareforupdate(), 261
$primarykey, 237
$print(), 94, 386
$printfile, 380
$printheight, 367
$printif, 368
$printrecord(), 376, 383
$printsection(), 383
$printtotals(), 383
$programname, 277, 328
$protocolversion, 307
$protoversion, 295
$proxyas(), 258
$query(), 296
$queryinfo(), 297
$queryresult(), 297
$querytimeout, 277, 328, 341
$readcharacter(), 415
$readonly, 308
$redraw(), 78, 92
$refilter(), 179
$remove(), 144, 167
List column, 169

$removeduplicates(), 168, 174


$removestringtable(), 422
$reportdataname, 380
$reportfield, 381
$reportfile, 380
$reporttoolbarpagepreview, 372
$reporttoolbarscreen, 372
$reset(), 309
$restrictpagewidth, 381
$results(), 191, 224
$resultspending, 187, 188
$resume(), 108
$revertlistdeletes(), 178
$revertlistinserts(), 178
$revertlistupdates(), 178
$revertlistwork(), 178
$righttoleft, 417
$rollback(), 206, 220, 299
$root, 25, 72
$rowcnt(), 422
$rowcount, 305
$rowid, 418, 426
$rownumber, 176
$rowpresent, 175, 176
$rowsaffected, 246
$rowsfetched, 247
$rpc(), 204, 224
$rpcdefine(), 204, 220
$rpcparameters(), 202, 224
$rpcparamspending, 279
$rpcprocedures(), 202, 225, 298
$savelistdeletes(), 177
$savelistinserts(), 177
$savelistupdates(), 177
$savelistwork(), 177
$savestringtable(), 422
$scale, 383
$schema, 308
$schemas, 236
$search(), 167, 172
$searchcalculation
List filter, 179
$select(), 161, 244, 247
$selectdistinct(), 244, 248
$selected, 170, 173
$selectnames(), 195, 220, 245, 252
$sendall(), 79
$sendallref(), 79
$senddata(), 379, 400

471

Index
$sendformfeed, 381
$sendtext(), 379, 400
$sequencetoint, 308
$serializable, 308
$serverdebuginfo(), 297
$servershutdown(), 297
$serverstatus(), 297
$servertablename, 237
$servertablenames, 246
$service, 307
$sessionname, 246
$sessionpools, 215
$setcolumn(), 422
$setdatatypemapping(), 297, 301
$setdriver(), 342
$setinfo(), 332
$setoption(), 333
$setparam(), 400
$setremotepassword(), 278
$skipsection(), 383
$smartlist, 166, 174
$socket, 295, 299, 307
$sort(), 168, 173
$sorts, 369
$sqlclassname, 242, 246
$sqlerror(), 162, 246, 252
$sqlstate, 311
$sqlstripspaces, 213, 305
$sqltext, 187, 208
$startpage(), 383
$startuptaskname, 105
$state, 185, 186, 187, 206
$statementname, 186
$status, 175, 176
$stringtabledata, 420, 426
$stringtabledesignform, 426
$stringtablelocale, 426
$superclass, 216
$suspend(), 108
$tables(), 199, 225
$tasks, 104
$threadid, 295
$threadsafe, 295
$timezone, 307
$title, 377
$toolbars, 25
$top, 388
$topwind, 75
$total(), 170

472

$totc(), 168
$transactionmode, 205, 299
$transactionstatus(), 309
$truetext, 260
$trustedconnection, 328
$txncapability, 330
$undodeletes(), 245, 251
$undoinserts(), 245, 251
$undoupdates(), 245, 251
$undowork(), 245, 252
$unfilter(), 179
$unicode, 404
$unloadall(), 422
$unloadstringtable(), 422
$update(), 162, 244, 249
$updatenames(), 195, 220, 245, 253
$usage, 113
$usecursor, 208
$usefiledsn, 328
$uselogonprompt, 328
$useprimarykeys, 246
$useprogramname, 328
$usequalifiers, 329
$username, 185
$usetimezone, 308
$validateutf8, 406
$validref(), 153
$version, 115
$visible, 377
$waitforuser, 381
$wherenames(), 196, 220, 246, 254
$width, 388
$windowprefs, 381
$windows, 25, 72
$writecharacter(), 415
$writelob(), 279, 282
% numeric variables, 68
%% string variables, 68
Active task, 107
Add line to list command, 164
Add-Ons menu, 14, 16
Associating components, 459
Batch fetching, 190
Begin reversible block command, 90
Begin statement, 187
BEGIN statement, 206
Binary data type, 59
Binary objects, 214
Bind variables, 193

Reports
Blob size, 214
Boolean data type, 54
Branching Commands, 85
Break key, 88
Break to end of loop command, 88
Breakpoint command, 125, 129
Breakpoints, 125
Break on calculation, 126
Break on variable change, 126
Clear breakpoints, 125
Clear field breakpoints, 125
One-time breakpoint, 125
Browser, 9
Creating an object class, 147
Making a subclass, 137
SQL Browser, 28
Build list from file command, 164
Build list from select table command, 163
Building projects, 450
Calculate command, 80
calculated property, 398
Calculation errors, 92
Calculations
Omnis operators, 81
Square bracket notation, 81
Type conversion in expressions, 82
Using constants, 83
Using the Calculate command, 80
Calling methods, 83
Can Be Null field option, 60
Cancel button, 88
Cannot Be Null field option, 60
Case command, 87
Catalog, 27
Entering sort fields, 369
String Tables, 420
Viewing variables, 70
Century range for dates, 57
Character data type, 52
Character Map Editor, 14, 405
Character mapping, 209
Character Mapping
in Unicode Mode, 407
Unicode, 404
Character normalization, 409
Character translation, 412
Charmap.exe, 209
Checking in components, 448
Checking in non-Omnis components, 443

Checking in Omnis classes, 441


Checking out VCS components, 446
Chunking LOBs, 214
Class Filter, 10, 46
Class types, 48
Class variables, 66, 159
Class Wizards, 49
Classes
Code, 48
Data classes, 50
File, 48
Hiding and Showing, 10
Making a subclass, 136
Menu, 49
Object, 48
Query, 48
Remote form, 48, 49
Remote task, 48
Report, 48
Schema, 48
Search, 49
Table, 48
Task, 48
Templates and Wizards, 49
Toolbar, 49
Window, 49
Clear class variables command, 66, 70
Clear list command, 172
Clear method stack, 84
clear(), 170
Clearing statements and sessions, 198
client.stb, 428
Clientware
Compatibility, 257
Clipboard report device, 373
Close task command, 108
Columns
Listing, 200
Combined mode, 15
Commands, 72
Comments, 120
COMMIT statement, 206
Compare Classes tool, 14
Component Store, 13, 20
Creating task classes, 106
componenticon property, 138
Components
Associating with a project, 459
Checking in or unlocking, 448

473

Index
Checking or copying out, 446
Component Store, 20
Deleting, 462
Managing, 458
Privileges, 458
Renaming, 462
Sharing components between projects, 459
Unlocking manually, 462
con(), 398
con() function, 60, 81
Connecting
JDBC, 342
Using methods, 183
Constants, 83
Container fields and events, 103
Context menus, 17
Control methods and passing events, 101
Copying out VCS Components, 446
CRB, 60
CREATE TABLE statement, 194
Creating a new project, 441
Current objects, 74
Current record buffer, 60
Current task, 108
Cursor results sets, 208
Custom methods, 143
Custom printing devices, 398
DAMs, 28, 182, 257
Unicode, 404
Data classes, 48, 50
Data type mapping, 50
Data dictionary, 199
Data File Conversion
Unicode, 403
Data mapping, 186
Data type mapping, 50
Data Type Mapping
DB2, 293
JDBC, 343
MySQL, 300
ODBC, 338
Oracle, 274
PostgreSQL, 314
Sybase, 288
Data types, 51
Binary, 59
Boolean, 54
Character, 52
Date time, 55

474

Field reference, 60
Item reference, 59
List, 58
Mapping Omnis to SQL, 197
National, 52
Number, 53
Object, 58
Object reference, 59
Picture, 58
Row, 58
Sequence, 57
Databases
Describing your database, 199
Date time data type, 55
Date time data types
Date and time calculations, 56
Date ranges, 57
Long date and time, 56
Short date, 55
Short time, 56
Date values, 213
DB2, 290
Connecting, 291
Data Type Mapping, 293
Dates, 291
Reserved words, 292
Transactions, 291
Troubleshooting, 292
DDE/Publisher report device, 375
Debug next event, 128
Debugger
Adding comments, 120
Execution errors, 121
Go point, 120
Private methods, 122
Stepping through methods, 121
Tracing methods, 122
Debugger commands, 129
Debugger options, 128
Debugging methods, 119
Breakpoints, 125
Inspecting variable values, 123
Method stack, 127
Using the method checker, 130
Watching variable values, 124
DECLARE, 208
Default classes, 46
Startup task, 46
System classes, 46

Reports
Default command, 87
Default library name, 44
Default task, 105
Define list command, 160
Define list from SQL class, 242
Delete Unused Variables, 69
Deleting data, 249
Descending sort option, 369
Describing results, 191
Describing your database, 199
Design mode, 15, 104
Design tasks
Checking out, 465
Desktop toolbar, 15
Devices for printing, 371
Diagnostic messages, 129
Disable debugger at errors, 128
Disable debugger method commands, 128
Discard event option, 99
Disk report device, 373
Do code method command, 83, 95, 109
Do command, 59, 76
Do default command, 80, 144, 386
in $print() method, 391
Do inherited command, 80, 142
Do method command, 66, 83, 95, 143
Do redirect command, 80, 144
Else command, 85
Else if command, 85
Empty values, 60
Enable cancel test at loops command, 88
End If command, 85
End of loop test, 88
End of report section, 363
End print command, 376
End reversible block command, 90
End statement, 187
Enter data command
Event processing, 102
Environment
Fonts, 12
Error handlers, 91
Errors
Calculations, 92
Escaping from loops, 88
evAfter, 95
evBefore, 95
evCanDrop, 98
evClick, 93

evClose, 100
evCloseBox, 100
evDrag, 98
evDrop, 98
Event handling methods, 64
Discarding events, 99
On command, 95
Quit event handler command, 98
Event messages, 93
Event parameters, 93
Event processing
Enter data mode, 102
Event queue, 103
Events
Mouse, 97
Events and messages
Container fields and events, 103
Control methods and passing events, 101
Event handling methods, 94
Queuing events, 103
Window events, 99
Events, discarding, 99
Events, queuing, 103
Events, window, 99
evKey, 101
evMouseDouble, 97
evMouseDown, 97
evMouseEnter, 97
evMouseLeave, 97
evMouseUp, 97
evRMouseDouble, 97
evRMouseDown, 97
evRMouseUp, 97
evWillDrop, 98
Examples, 9
External components
Events, 114
Functions, 114
HTML printing device, 398
HTML report objects, 401
Java beans, 115
Notation, 113
Properties, 114
Version notation, 115
External objects, 216
External Objects, 154
Events, 155
F1, Help key, 41
Fetch next row, 163

475

Index
Fetching data, 248
Fetching results, 188
External files, 189
Omnis variables, 189
Field reference data type, 60
File report device, 374
Fileops, 415
Find and Replace, 19
Find Next, 19
Flag, 72
Flow control commands, 85
Folders button, 9
Folders, Library, 10
Follow start mode, 366
Fonts, 393
Environment, 12
For each line in list command, 87
For field value command, 87
For Loops, 87
Formatting strings, 60
Formfile, 414
Frombottommarg start mode, 367
Fromend start mode, 367
Fromtop start mode, 366
Fromtopmarg start mode, 367
Get Info, 462
Get statement, 187
Go Point, 120
Hash variables, 67
Help, 41
Help tips option, 22
History, Revision, 460
Hold Updates option, 21
HTML device, 398
Parameters, 399
Sending text or data, 400
HTML report device, 374
HTML report objects, 401
If canceled command, 88
If command, 85
Indexes
Listing, 200
Indirection
Using Square bracket notation, 82
Inheritance, 136
Overloading and overriding, 138
Inheritance notation, 141
Calling properties and methods, 141
Do inherited command, 142

476

Inherited fields and objects, 142


Referencing variables, 142
Inheritance tree, 140
Inheritance, Reports, 392
inheritedcolor property, 137
inheritedorder property, 138
Initial value of variables, 69
Input masks, 60
INSERT statement, 195
Inserting data, 249
Inserting methods, 118
Instance variables, 66, 159
Instances
Private instances, 109
Interface Manager, 156
islabel property, 397
isnull() function, 60
issupercomponent property, 138
Item reference data type, 59
Item references, 73
Java beans, 115
JDBC, 341
Data type mapping, 343
Transactions, 342
jst() function, 60
kComponent, 114
kerrSuperclass, 141
Key events, 101
kFetchError, 248
kFetchFinished, 248
kFetchOk, 248
kFitOnPage, 368
kSessionCharMapLatin1, 407
kSessionCharMapNative, 211, 405
kSessionCharMapOmnis, 211, 405
kSessionCharMapRoman, 407
kSessionCharMapTable, 211, 405
kSessionLoggedOff, 185
kSessionLoggedOn, 185
kSessionTranManual, 205
kStatementIndexAll, 201
kStatementIndexNonUnique, 201
kStatementIndexUnique, 200
kStatementServerAll, 199
kStatementServerTable, 199
kStatementServerView, 199
kStatementStateClear, 187
kStatementStateExecDirect, 188
kStatementStateExecuted, 187

Reports
kStatementStatePrepared, 186
kUnknown, 205
Label reports, 397
labelcount property, 397
labelwidth property, 397
Large objects, 214
Libraries, 43
Default name, 44
Multi-library projects, 45
Private libraries, 110
Library
Properties, 44
Library folders, 10
List commands and smart lists, 180
List data type, 58, 158
List variables, 242
list() function, 164
Listing columns, 200
Listing indexes, 200
Listing tables, 199
Listing views, 199
Lists
Accessing columns and rows, 165
Building from Omnis Data, 164
Building from SQL Data, 163
Building list variables, 163
Clearing list data, 172
Declaring list variables, 159
Declaring row variables, 159
Defined from a query class, 160
Defined from a schema class, 160
Defining list variables, 160
Defining row variables, 160
Dynamic redefinition, 171
List and row functions, 164
Manipulating lists, 171
Merging lists, 173
Programming, 158
Properties and methods, 166
Properties of a list cell, 170
Removing duplicate values, 174
Searching lists, 172
Selecting list lines, 172
Smart lists, 174
Sorting lists, 173
Variable notation, 165
Viewing List Values, 164
Load error handler command, 91
Load from list command, 165

LOBs, 214
Oracle, 267
Sybase, 282
Local variables, 66, 68, 159
Locale Identifier, 412
locale(), 412, 429
Localization, 417
Localizing Omnis, 430
Omnis, 428
Remote Forms, 426
Long date and time type, 56
Loops, escaping from, 88
lst() function, 165
Make schema from server table command,
238
Managing components, 458
Mapping
Data types, 50
Memory report device, 374
Menus
Context menus, 17
Omnis menu bar, 15
Menus, Studio, 12
Merge list command, 173
Message boxes, 93
Method checker
Fatal errors, 131
Level 1 warnings, 132
Level 2 warnings, 133
Method Checker, 14, 130
Method editor, 118
Adding variables, 67
Method Editor
Adding a method to a report class, 376
Adding a method to a report field, 376
Command palette, 118
Context menus, 18
Declaring list or row variables, 159
Event handling methods, 94
Menubar and toolbar, 118
Method names and definition, 118
Variables panes, 118
Watch variables pane, 119
Method lines, 71
Method stack, 127
Stack list, 127
Methods, 71
Calculate command, 80
Calling methods, 83

477

Index
Commands, 72
Custom methods, 143
Debugging, 119
Debugging methods, 117
Do command, 75
dragging from the Interface Manager, 157
Error handling, 91
Event handling, 94
Executing using the Do command, 75
Field methods, 94
Flow control commands, 85
Inheriting methods, 138
Inserting and Editing, 118
Line methods, 94
Line numbers, 119
Message boxes, 93
Notation, 72
Overriding inherited methods, 139
Performance, 134
Quitting methods, 84
Redrawing objects, 92
Report and Field Methods, 375
Reversible blocks, 90
Sequence Logging, 135
Tool methods, 94
Using the method checker, 130
Window control, 101
Mouse events, 97
MultipleSelect property, 172
Multi-threaded server, 215
MySQL, 295
Data Type Mapping, 300
Logging on, 298
Transactions, 299
Troubleshooting, 305
Narrow Sections option, 364
natcmp() function, 432
National data type, 52
National Sort Ordering
Localization, 431
New Class templates, 49
New page sort option, 370
New Users, 14, 16
Newpage option, 366
nfc(), 410
nfd(), 410
No/Yes message, 93
Non-Omnis components
Checking in, 443

478

Nopage option, 366


Notation
Current objects, 74
External components, 113
Inheritance, 141
Item references, 73
List variables, 165
Object tree, 72
Notation Helper, 26
Notation Inspector, 13, 24, 72
$root, 25
Null values, 60
Number data type, 53
Floating point numbers, 54
Object classes, 147
Creating an object class, 147
Object data type, 58
Object orientation, 136
Custom properties and methods, 143
Inheritance, 136
Object classes, 147
Object reference data type, 59
Object references, 152
ODBC, 327
Administration, 336
Connecting, 333
Data type mapping, 338
Transactions, 334
Troubleshooting, 338
ODBC Admin tool, 14
OK message, 93
Omnis
Localization, 430
Object orientation, 136
Omnis Help, 41
Omnis libraries, 43
Omnis Menu Bar, 15
Omnis Preferences, 11
Omnis Report Wizard, 362
Omnis VCS, 40, 43, 435
OmnisLOC, 430
omnisloc.df1, 430
On command, 95, 99, 119
On default command, 96
Open library command
Do not open startup, 106
Open task instance command, 107
Open trace log, 128
Open trace log command, 122

Reports
Operator precedence, 81
Optimizing methods, 89
Optimizing Program Flow, 89
Options, 464
Options (Preferences), 11
Oracle, 258
Connecting, 261
Data type mapping, 274
LOBs, 267
Troubleshooting, 275
Unicode, 262
Oracle 8, 267
Oracle 9i, 271
Overloading properties, methods, and
variables, 138
Owner of VCS project, 458
Page footer section, 363
Page header section, 363
Page layout, 389
Page setup, 385
pagefooter property, 364
pageheader property, 364
pagemode property, 366
pagespacing property, 366
Parameter variables, 66, 68
Reordering in the method editor, 68
Pass to next handler option, 101
Pass to other handlers option, 99
pEventCode, 93
Picture data type, 58
pKey, 101
PL/SQL, 263
Port Profile editor, 14
Port profiles, 395
Port report device, 373
Position sections, 367
Positioning
Report objects, 387
Positioning section, 363
PostgreSQL, 305
Client Libraries, 305
Data Type Mapping, 314
Logging on, 311
Remote Procedure Calls, 312
Transactions, 312
Troubleshooting, 318
Preferences, 464
Preferences, Omnis, 11
Prepare for print command, 376

Preview reports, 372


Print Destination, 12
Print device notation, 377
Methods, 378
Print record command, 376
Print report command, 376
Print report from disk command, 373
Print report from memory command, 375
Printer
Report device, 372
Printer Escapes, 396
Printing errors, 375
Printing preferences, 380
Printing Reports, 371
Private instances, 109
Private libraries, 110
Privileges, 458
Process event and continue command, 102
Programming
SQL, 181
Programming and manipulating lists
Accessing list columns and rows, 165
Building list variables, 163
List and row functions, 164
Projects
Building, 450
Creating a session, 438
Owners, 458
Setting up, 437
Viewing the contents of a project, 443
Prompt for input, 93
Properties
dragging from the Interface Manager, 157
History lists, 176
Inheriting properties, 138
List cells, 170
of a library, 44
Overloading inherited properties, 139
Property Manager, 21
Properties and methods
List columns, 168
List rows, 170
Lists, 166
Property Manager, 13, 21
Context menu, 21
Showing Help tips, 22
pRowCount, 188
pSystemKey, 101
pTableRef, 188

479

Index
Query classes, 62, 236, 238
Calculated columns, 239
Notation, 239
Queue commands, 103
Quit all if canceled, 84
Quit all methods, 84
Quit command, 84
Quit event handler command, 98, 101
Quit method, 84
Quit method command, 99
Quit Omnis, 84
Quit to enter data, 84
Quitting methods, 84
Recent classes, 10
Record section, 363
Record Sequencing Number (RSN), 57
recordspacing property, 367
Redraw command, 92
Redrawing objects, 92
Ref Cursor data types, Oracle 8, 269
Remote Forms
Localizing, 426
Remote Procedure Calls
Sybase, 283
Remote Procedures, 202
Calling, 204
Listing, 202
Listing parameters, 202
Renaming objects, 20
Repeat Loop, 86
repeatfactor property, 397
Report and Field Methods, 375
Report destination dialog, 371
Report devices, 371
Clipboard, 373
DDE/Publisher, 375
Disk, 373
File, 374
HTML, 374
Memory, 374
Port, 373
Preview, 372
Printer, 372
RTF, 374
Screen, 372
Report field methods, 386
Report fonts, 393
Report heading section, 363
Report inheritance, 392

480

Report instance methods, 383


Report object positioning, 387
Report section methods, 386
Report sections, 366
Report wizards, 362
Reports, 361
Reports
Report tools, 362
Reports
Sections, 363
Reports
Sections, 363
Reports
Page mode, 366
Reports
Start mode, 366
Reports
Record spacing, 367
Reports
Position sections, 367
Reports
Sorting and Subtotaling, 369
Reports
Subtotal sections, 370
Reports
Printing, 371
Reports
Report and Field Methods, 375
Reports
Current device, 377
Reports
Print device notation, 377
Reports
Printing preferences, 380
Reports
Labels, 397
Reports
Excluding empty lines, 398
Reports
Calculated fields, 398
Reports
HTML device, 398
Reports in the VCS, 467
Results set
Describing, 191
Reversible blocks, 90
Revisions, 460
Right to Left data entry, 417
Right-clicking

Reports
Context menus, 17
rnd() function, 54
ROLLBACK statement, 206
Row data type, 58, 158
Row variables, 242
row() function, 164
RPC method, 204
RTF report device, 374
Runtime mode, 15, 104
Save debugger options, 128
Schema classes, 61, 236
Building, 201
Notation, 236
Scope
Rescoping a variable, 69
Scope of variables, 65
Screen reports, 372
SEA commands, 91
Searching lists, 172
Section print height, 367
Section properties
Page Mode, 366
Record spacing, 367
Start Mode, 366
Sections, position marker, 366
Sections, Report, 363
Sections, Reports, 366
Select statement, 247
SELECT statement, 195, 208
Send to trace log command, 97, 129
Sequence data type, 57
Sequence Logging, 135
Server
Sending SQL to, 186
Server specific programming, 257
Server tables
Creating from schema and query classes,
241
Session methods, 219
Session objects, 182
Creating, 184
Logging on, 184
Session pools, 215
Session properties, 221
Session, Creating a, 438
Sessions, 28
Clearing, 198
Set reference command, 59, 73
Setting up a project, 437

Setting VCS options, 464


Short date data type, 55
Short time data type, 56
Signal error command, 91
Signing in to the VCS, 439, 446
Smart lists, 174
Change tracking methods, 177
Committing changes to the server, 179
Enabling smart lists, 174
Filtering, 178
History list, 175
List commands, 180
Properties of history lists, 176
Properties of rows in history lists, 176
Tracking changes, 177
Sort by Property Name option, 21
Sort fields in a report, 369
Sort list command, 173
Sorting reports, 369
SQL
Fetching results, 188
Sending to server, 186
Server-Specific Programming, 257
Session objects, 182
Statement objects, 182
Using square bracket notation, 192
SQL Browser, 28
SQL classes
Notation, 236
SQL errors, 196, 252
SQL methods, 61, 62
SQL programming, 181
Overview, 182
SQL queries, 194
SQL Statement Objects, 185
SQL statements
Executing, 187
Preparing, 186
sqlclassname property, 160
Square bracket notation, 81
Using SQL, 192
Sta
command, 187, 192
Standard toolbar, 12
startmode property, 366, 398
startspacing property, 367, 398
Startup task, 46, 105
Stop it running, 106
Startup_Task class, 105

481

Index
Statement methods, 224
Statement objects, 182
Creating, 185
Statement properties, 225
Statements
Clearing, 198
stgetcol(), 427
stgettext(), 427
String labels, 417
String Table Editor, 14, 417, 419, 428
String Tables
Catalog, 420
Functions, 421
Programming, 423
STRINGID, 419
STRINGID Locale, 420
StringTable component, 417
Stripping spaces
SQL, 213
stsetcol(), 427
Studio Browser, 9, 13
Class Wizards, 49
New Class, 49
Studio menus, 12
Studio toolbars, 12
studio.stb, 428
style(), 396
Subclasses
Making a subclass, 136
Subtotal heading 1 to 9 sections, 363
Subtotal heading section, 363, 370
Subtotal sections, 370
Subtotals in reports, 369
Subtotals level 1 to 9 sections, 363, 370
Subtotals sort option, 369
superclass property, 138
Superclasses
Checking out, 464
Switch command, 87
Sybase, 277
Connecting, 279
Data type mapping, 288
Error handling, 281
Lobs, 282
Multiple select tables, 280
Program Name, 280
Remote procedure calls, 283
Troubleshooting, 286
sys(85) function, 97

482

sys(86) function, 97
System classes, 46
System tables, 441, 452
Table classes, 62, 236, 242
Notation, 242
Table instances, 242
Methods, 247
Notation, 244
Tables
Listing, 199
task $control(), 101
Task classes, 104
Active task, 107
Closing tasks, 108
Creating tasks, 106
Current task, 108
Default and startup, 105
Design task, 109
Multiple tasks, 111
Opening tasks, 107
Private instances, 109
Private libraries, 110
Task variables, 108
Task context switch, 107
Task variables, 66, 69, 159
Testspace option, 366
text property, 398
Tools toolbar, 14
totalmode property, 370
Totals section, 363, 370
Trace all methods, 128
trace log, 122
Trace Log, 14, 16
Trace off command, 129
Trace on command, 129
Transaction modes, 205
Automatic, 205
Manual, 205
Server, 207
Transactions, 205
Type conversion in expressions, 82
unichr(), 412
Unicode, 402
Character Mapping, 404
DAMs, 404
Data File Conversion, 403
Data Handling, 413
What is Unicode?, 402
Unicode Clients, 412

Reports
unicode(), 412
uniconv(), 413
Unlocking components, 448, 462
Until break command, 88
Update files command, 58
UPDATE statement, 195
Updating data, 249
Upper case sort option, 369
Use search option, 173
User privileges, 458
userecspacing property, 367
Users
Adding and managing users, 440
Using tasks
Closing tasks, 108
Creating task classes, 106
Current and active tasks, 107
Default and startup tasks, 105
Multiple tasks, 111
Opening tasks, 107
Private instances, 109
Private libraries, 110
Task variables, 108
Using Tasks, 104
Values List, 123
Variable context menu, 70, 123
Variable Declaration and Scope, 65
Variable menu command, 129
Variable tips, 70
Variables, 65
Adding a variable, 67
Adding local variables, 68
Adding parameter variables, 68
Adding task variables, 69
Bind variables, 193
Building, in lists, 163
Class variables, 66
Context menus, 18
Declaring, in lists, 159
Defining, in lists, 160
Deleting unused, 69
Hash variables, 67
Initial values, 69
Instance variables, 66
Item references, 73
Local variables, 66
Naming, 68
Overriding inherited variables, 139

Parameter variables, 66
Task variables, 66
Viewing in the Catalog, 70
Watched, 124
VCS, 40, 43, 45, 435
Build options, 466
Check in options, 465
Check out options, 464, 465, 466
Checking in non-Omnis components, 443
Checking in Omnis classes, 441
Creating a new project, 441
Deleting components, 462
Display options, 464
Labels, 456
Managing components, 458
Renaming components, 462
Setting up a project, 437
Signing in to the VCS, 439
VCS Component services, 462
VCS Components
Getting info, 462
VCS Options, 464
VCS Reports, 467
VCS Revision History, 460
Version Control System, 40, 45, 435
Version numbers, 442
View menu
Component Store, 20
View toolbar, 13
Viewing the contents of a project, 443
Views
Listing, 199
watched variable, 124
Web client
Session pools, 215
Web Client Tools, 14
Welcome start page, 8
WHERE clause, 196
While command, 86
While Loop, 86
Wizards
Omnis Report Wizard, 362
Working message, 93
XCOMP folder, 113
XML
Oracle, 271
Yes/No message, 93

483

You might also like