You are on page 1of 34

Progress Software Corporation

Building High Performance


Applications with the
Progress Oracle DataServer

Author:

Oriana Merlo

Updated: December, 1998

Building High Performance Applications with the Progress Oracle DataServer

Table of Contents
Table of Contents.................................................................................................................................... ii
Executive Summary................................................................................................................................ 1
Introduction............................................................................................................................................ 2
High Performance vs. Database Independence............................................................................... 2
DataServer Configurations..................................................................................................................... 3
Local DataServer and Local Oracle Database ....................................................................................... 3
Local DataServer and Remote Oracle Database .................................................................................... 3
Remote DataServer and Local Oracle Database .................................................................................... 4
Remote DataServer and Remote Oracle Database ................................................................................. 4
SQL*Net or Net8 vs. Progress Networking .......................................................................................... 4
Database Design ..................................................................................................................................... 5
Naming Conventions ........................................................................................................................... 5
Database Limitations ........................................................................................................................... 5
Data Types .......................................................................................................................................... 5
Additional Database Objects Required ................................................................................................. 5
Arrays.................................................................................................................................................. 6
Case-Insensitive Indexes ...................................................................................................................... 6
RECIDs............................................................................................................................................... 6
Word Indexes ...................................................................................................................................... 7
Unknown Values / NULLs / Zero-Length Character Strings ................................................................. 7
Fixed vs. Variable Length Character Strings in Oracle.......................................................................... 7
Trailing Blanks .................................................................................................................................... 7
Progress To Oracle Database Conversion Utility .................................................................................. 8
Application Design ................................................................................................................................. 9
Unsupported Syntax............................................................................................................................. 9
Utilizing Oracle-Specific Functionality ................................................................................................ 9
Stored Procedures ........................................................................................................................... 9
Native Oracle SQL Syntax Support .................................................................................................. 9
Optimizer Hints ............................................................................................................................... 9
Transactions ........................................................................................................................................ 9
Stored Procedures and Transaction Scoping...................................................................................10
Constraint Violations / Trigger Execution.......................................................................................10
Triggers..............................................................................................................................................10
Record Locking ..................................................................................................................................10
No SHARE-LOCK Support in Oracle..............................................................................................11
Automatic Optimistic Locking Support............................................................................................11
Cursor Repositioning ..........................................................................................................................11
RECIDs and ROWIDs ........................................................................................................................12
Record Scoping / Availability .............................................................................................................13
Ordering of Records............................................................................................................................14
Query Tuning..........................................................................................................................................14
Field Lists ......................................................................................................................................14
Lookahead Cursors ........................................................................................................................14
Progress 4GL vs. SQL ....................................................................................................................15
Join-By-SQLDB .............................................................................................................................16

December, 1998

Page ii

Building High Performance Applications with the Progress Oracle DataServer

Error Messaging .................................................................................................................................16


Distributed and Batch Processing with an Oracle Database ..................................................................16
Mass Database Modifications..............................................................................................................16
Oracle Query Resolution.....................................................................................................................16
INDEXED-REPOSITION Support......................................................................................................17
Deployment Considerations ..................................................................................................................18
Building Progress Executables ............................................................................................................18
Schema Holders..................................................................................................................................18
Oracle Database Changes and the Schema Holder ...............................................................................18
Incremental Schema Difference File....................................................................................................18
Code Recompilation Due to Schema Changes .....................................................................................19
Startup Parameters..............................................................................................................................20
Migrating Multiple Progress Databases ...............................................................................................20
Progress Runtime Licenses .................................................................................................................21
Database Conversion Utilities ........................................................................................................21
DataServer and Database Administration Utilities..........................................................................21
Troubleshooting and Performance Tuning...........................................................................................22
Query/Browse Performance ................................................................................................................22
Version 7 Progress Oracle DataServer Performance ......................................................................22
Version 8 Progress Oracle DataServer Enhancements ....................................................................22
Version 9 Progress Oracle DataServer Enhancements ....................................................................22
Skipping Schema Verification.............................................................................................................22
Debugging DataServer Applications....................................................................................................22
Debug SQL.....................................................................................................................................23
Debug Extended .............................................................................................................................23
Debug Cursor.................................................................................................................................24
Debug Databind.............................................................................................................................25
Debug Performance .......................................................................................................................26
Debug Summary.............................................................................................................................27
Debug Verbose...............................................................................................................................27
Appendix A............................................................................................................................................30

December, 1998

Page iii

Building High Performance Applications with the Progress Oracle DataServer

Executive Summary
The past decade has seen many companies invest a significant amount of both time and resources into
establishing corporate database standards. With hardware, operating systems and networking products
giving way to open technologies, those same companies are frustrated in their efforts to grow by being
inextricably bound to application suppliers who provide solutions that run only on their chosen database.

A single database system today is capable of acting as the source for a variety of applications, from
traditional on-line transaction processing (OLTP) and decision support systems (DSS), to todays currently
hot technologies like data mining and internet transaction processing (ITP). Customers want high
performing solutions, and they want them to fit in with their existing operating environments, without
having to duplicate data to a wide variety of different database management systems.

Progress Software Corporation's (PSC) DataServer technology allows applications created with the
Progress 4GL or Progress WebSpeed development environments to connect to a variety of nonProgress data sources. The DataServer accepts the request for data from the application, translates it into a
format and syntax suitable for the underlying database, and passes the request on. The data source then
accepts the request, processes it as if it were a native client, and sends the information back to the
DataServer. The DataServer will then adjust the result set into the format expected by the application
before passing it on.

This paper will help you create high performance applications with the Progress 4GL and WebSpeed
toolsets to integrate with an Oracle relational database management system (RDBMS). The focus of this
paper is on Progress tools and technology. It explains how the Progress Oracle DataServer supports the
development and delivery of high performance applications on an Oracle database.

Progress provides you with the tools to build mission-critical applications for a wide variety of deployment
configurations, without changing the application logic. This allows developers to focus on solving business
problems, not reacting to changes in the computing infrastructure.

December, 1998

Page 1

Building High Performance Applications with the Progress Oracle DataServer

Introduction
Creating an application to run efficiently over an Oracle relational database management system (RDBMS)
requires the integration of a number of technologies: the development toolset used to create the application,
the underlying Oracle database technology, a knowledge of operating systems and networked
environments, and the connectivity software used for access to the Oracle database.
The Progress 4GL and WebSpeed development tools are tightly integrated with the Progress RDBMS,
however, the Progress Oracle DataServer allows you to use these toolsets to develop applications that can
be deployed with an Oracle RDBMS. The Progress Oracle DataServer provides optimized database
connectivity to the Oracle database. This connectivity technology, however, does require thorough
understanding. While the Progress 4GL and WebSpeed toolsets make it easy to develop on-line transaction
processing (OLTP) and internet transaction processing (ITP) applications, subtle differences in the Oracle
and Progress databases make it necessary for developers to be mindful of their data source during the
application development phase. New development work can be undertaken so that resulting applications
can run equally well over either data manager. Application developers who have existing Progress 4GL or
WebSpeed applications may find that some parts of their application logic may need to be rewritten to cater
to these database differences.

High Performance vs. Database Independence


When creating a database independent application, developers look for features that are common among all
database managers, to avoid having to re-code applications for each different data source. This can often
lead to the sacrifice of many features native to an RDBMS (such as word-index capabilities, stored
procedures, or index optimizations). A high performance application on the other hand, will make use of
these features and any other means available to them in order to obtain maximum performance.
The Progress DataServer technology, when combined with the Progress 4GL and WebSpeed development
toolsets, offers a complete environment in which to build applications that provide high performance in a
database independent environment.
This document aims to highlight some of the issues that developers should be aware of when using the
Progress Oracle DataServer to design high performance, database independent applications with the
Progress 4GL or WebSpeed toolsets accessing an Oracle database.

December, 1998

Page 2

Building High Performance Applications with the Progress Oracle DataServer

DataServer Configurations
There are four possible configurations when using the Progress Oracle DataServer. Details of each
configuration are given below.

Local DataServer and Local Oracle Database


Figure 1 shows a local DataServer configuration where all the Progress software modules run on a single
machine. In this case, the Oracle database is also local. This configuration is used most often with terminalbased users and where batch mode processing is required.

Schema
Holder
Oracle
Progress

Client

Progress Oracle
DataServer

Machine 1

Figure 1: Local DataServer and Local Oracle Database Configuration

Local DataServer and Remote Oracle Database


Figure 2 shows a local DataServer accessing an Oracle database on another machine through SQL*Net
or Net8 (Oracles networking software). Net8 can be used instead of SQL*Net when accessing an
Oracle8 database. In this configuration there are no Progress processes running on the Oracle RDBMS
machine. This configuration is often used when high performance connectivity is required across a LAN
or WAN, and there is no requirement for 4GL-based batch processing on Machine 2.

Progress
Client

Schema
Holder

Progress Oracle
DataServer

Oracle
Networking

SQL*Net
or Net8

SQL*Net
or Net8

Oracle
Machine 2

Machine 1

Figure 2: Local DataServer and Remote Oracle Database Configuration

December, 1998

Page 3

Building High Performance Applications with the Progress Oracle DataServer

Remote DataServer and Local Oracle Database


Figure 3 shows a configuration where a client accesses a remote Progress Oracle DataServer through
Progress networking. Here, the Oracle database and the DataServer are running on the same machine.
(Note that the schema holder can be located on either the client or the server.) This hybrid environment is
often used when a combination of client/server and host-based processing needs to occur against the Oracle
database.

Progress
Client

Progress Oracle
DataServer

Schema
Holder
Machine 1

Progress
Networking

Schema
Holder

Oracle

Machine 2

Figure 3: Remote DataServer and Local Oracle Database Configuration

Remote DataServer and Remote Oracle Database


Figure 4 shows a configuration for a client using remote Progress Oracle DataServer, and accessing an
Oracle database remote to the DataServer. This configuration could be used when a combination of local
and remote clients are required to access an Oracle database on a platform not supported by Progress.

Progress
Client
Schema
Holder
Machine 1

Schema
Holder

Progress
Networking

Progress Oracle
DataServer

SQL*Net
or Net8

Oracle
Networking

Machine 2

Oracle

SQL*Net
or Net8

Machine 3

Figure 4: Remote DataServer and Remote Oracle Database Configuration

SQL*Net or Net8 vs. Progress Networking


The decision whether to use SQL*Net, Net8 or Progress Networking is influenced by many factors. Apart
from the deployment flexibility shown in the above configurations, consideration needs to be given to
current implementations on client and server platforms. If the Oracle database to be accessed resides on an
operating system not supported by PSC, (such as IBM's OS/390), you can only get to that database by
putting the DataServer on a client or middle-tier machine, and using either SQL*Net or Net8 networking
software to get across to the Oracle database. Also, it may be possible that networking communications
(either SQL*Net, Net8, or Progress Networking) have already been set up between the client and server
machines. In this instance, introducing new networking stacks on both machines may merely introduce
unwanted (and unnecessary) processing overhead.
Informal benchmarking has shown that there are minimal performance differences between using SQL*Net
and Progress Networking to get to an Oracle database. In all deployment situations, however, you should
individually test your own configurations for the best possible solution for your environment.

December, 1998

Page 4

Building High Performance Applications with the Progress Oracle DataServer

Database Design
Because of the inherent differences between the Progress and Oracle relational database managers, care
needs to be taken when designing a database architecture for Oracle to be accessed by a Progress-based
application. The following sections discuss the differences between the Progress and Oracle data managers,
and how the DataServer resolves them.

Naming Conventions
The Oracle database management system has certain naming conventions that must be adhered to for
naming database objects such as tables, columns, sequences, indexes, etc. These conventions forbid the use
of some special characters that are otherwise acceptable in a Progress RDBMS. The Oracle product
documentation will offer more details on characters to be avoided. As a general rule, avoid the use of
hyphens (-) and percent signs (%) in all object names.
Be mindful of any limits on the length of object names within the Oracle database (Progress has a
maximum of 32 per table name, Oracle only 30) remembering that the Progress Oracle DataServer may
need to append extra characters to an object name to support extended Progress 4GL compatibility. In
general, try and limit your object names to 25 characters.
The Oracle database management system has its own set of reserved words that cannot be used to name
database objects. Avoid the use of these reserved words (as well as all Progress reserved words) when
naming objects in an Oracle database.
Please refer to the Progress Oracle DataServer Guide for further information.

Database Limitations
Depending on the version of the Oracle RDBMS, there may be certain physical limits imposed by the
database that can cause problems when converting a Progress database to this database management
system. One example of a particularly problematic limitation is Oracle7 s limit of 254 columns in a
single table. (This limitation has been increased to 1,000 columns in Oracle8.) There are several instances
where an equivalent Oracle table will require more columns than its Progress equivalent, such as to
accommodate Progress arrays, case-insensitive indexes, and RECID values. These scenarios are outlined in
more detail below. Appendix A contains a sample Progress 4GL program to calculate the number of
columns a Progress table would need in an equivalent Oracle table.
For further information on other limits, please refer to the Progress Oracle DataServer Guide, and your
Oracle documentation.

Data Types
The Oracle data manager has specific data types that vary from those of the Progress database. The
Progress Oracle DataServer translates these data types as closely as possible into Progress equivalents.
When a particular data type has more than one valid Progress equivalent, the DataServer supplies a default
data type. The Progress schema holder contains these Progress data type mappings for each underlying
column. You can manually change the default data type mapping in the schema holder using the Progress
Data Dictionary. One particular example is the single digit data type NUMBER(1) in Oracle. This can map
to a single digit INTEGER data type (9(1)), or a LOGICAL data type in Progress.
For further details on Oracle data types and their equivalent Progress mappings, please refer to the Progress
Oracle DataServer Guide.

Additional Database Objects Required


In order to make the Progress 4GL 100% compatible with the Oracle database, the Progress Oracle
DataServer requires that additional columns, indexes and sequences be created in the Oracle database:
December, 1998

Page 5

Building High Performance Applications with the Progress Oracle DataServer

If Progress arrays are used within an application, a separate column will need to be created in an
Oracle table for every element of the array.
If case-insensitive indexes are used within a Progress database, a secondary column and additional
index need to be created in the Oracle database to support case-insensitive indexed retrieval.
If Progress RECIDs are used within an application, additional columns and sequences must be created
in Oracle to support their use.
These additional database objects can be created automatically when using the Progress-to-Oracle
conversion utility, protoora. This utility is described in more detail later in this document.
Each of these scenarios is described in more detail later on in this document. These extra columns and
indexes are masked from the developer or end user by use of the Progress schema holder.
Please refer to the Progress Oracle DataServer Guide for further information.
Please note that the creation of multiple fields for array representation, the addition of columns to support
case insensitive indexing, and RECID columns for scrolling demand close investigation because of limits to
the number of columns per table and the number of components per index imposed by the Oracle7
RDBMS. Appendix A contains a sample Progress 4GL program to calculate the number of columns a
Progress table would need in an equivalent Oracle table.

Arrays
The Oracle data manager does not support arrays in the way the Progress RDBMS does. However, the
Progress Oracle DataServer allows you to extend this array support into an Oracle database. As an example,
a Progress array of 12 elements would be implemented in Oracle by creating 12 distinct fields in a certain
order, and with a specific naming convention (outlined in the Progress Oracle DataServer Guide). The
Progress Oracle DataServer will then recognize these fields as forming an array, which the 4GL can access
in its normal fashion.
Please note that the creation of multiple fields for array representation demands close investigation because
of limits to the number of columns per table imposed by the Oracle7 RDBMS. Appendix A contains a
sample Progress 4GL program to calculate the number of columns a Progress table would need in an
equivalent Oracle table.

Case-Insensitive Indexes
By default, all character indexes defined in a Progress database will be case-insensitive (for example, the
letter a is equivalent to A in a sorting algorithm). The Oracle RDBMS does not provide caseinsensitive indexing. Therefore, as an example, the letter a will sort differently than its uppercase
equivalent A. The Progress Oracle DataServer can mask this difference by supporting the use of a
specially named column in the Oracle table (storing only uppercase values of the original column), and an
index on that column. If this table is to be updated by non-Progress applications, then an Oracle database
trigger should also be created to populate this shadow column with an uppercase value of the original
column.
Please refer to the Progress Oracle DataServer Guide for more information on the naming conventions of
these columns and methods for populating them.
Please note that the addition of columns to support case-insensitive indexing demands close investigation
because of limits to the number of columns per table imposed by the Oracle7 RDBMS. Appendix A
contains a sample Progress 4GL program to calculate the number of columns a Progress table would need
in an equivalent Oracle table.

RECIDs
The Progress Oracle DataServer will support RECID functionality in an Oracle database through the use of
an additional unique integer column on the table (called PROGRESS_RECID). This additional column will

December, 1998

Page 6

Building High Performance Applications with the Progress Oracle DataServer

also require an index, and a specially named sequence to populate it. The Progress Oracle DataServer will
automatically increment the sequence, populate the PROGRESS_RECID field, and modify the index when
new records are added to the table through the Progress 4GL interface. If records are to be added to the
table from outside of a Progress environment, the PROGRESS_RECID field will need to be updated
manually. An Oracle database trigger is best suited to automating this process. Refer to the Application
Design section of this whitepaper for a further discussion of using ROWIDs and RECIDs.
Please note that the creation of PROGRESS_RECID columns demands close investigation because of
limits to the number of columns per table imposed by the Oracle7 RDBMS. Appendix A contains a sample
Progress 4GL program to calculate the number of columns a Progress table would need in an equivalent
Oracle table.

Word Indexes
Due to technical differences between the Oracle and Progress RDBMSs, word indexes are not supported
with the Progress Oracle DataServer. One possible workaround for this problem involves keeping the
column to be word indexed in a separate Progress database with links to the originating record in the Oracle
data manager.

Unknown Values / NULLs / Zero-Length Character Strings


The Oracle RDBMS does not support the concept of unknown values (represented as the ? value) as it
applies to a Progress database. The Progress Oracle DataServer extends Oracles functionality by allowing
for this unknown value. This is done by mapping the Progress unknown value to a NULL or a zero-length
character string in the Oracle database. This could have implications to unique indexing of existing data, as
Oracle allows only one NULL value per unique index.
Please refer to the Progress Oracle DataServer Guide for full details on how unknown values are handled.

Fixed vs. Variable Length Character Strings in Oracle


The Progress RDBMS stores character data in variable length format. This means that a 20 character string
will always be stored as 20 bytes in the database (when using single byte character sets), while a 16
character string will always be stored in 16 bytes, regardless of how the column is defined in the table.
Oracle allows both variable and fixed length string storage. If a column in Oracle is defined as type CHAR
with 18 characters, then it will store 18 characters, no more and no less. Hence, our 20 character string will
be truncated to 18 characters, and our 16 character string will contain two trailing blanks. Oracle also has
the VARCHAR2 dataype that allows a column to be defined as being of variable length up to a userdefined maximum limit. This means that any character strings longer than the specified maximum will be
truncated. Therefore, a VARCHAR2 column with a maximum length of 18 characters will truncate our 20
character string to 18 characters when stored in the Oracle database, but the 16 character string will remain
16 characters in length.

Trailing Blanks
Oracle handles trailing blanks differently than Progress, even when the field is defined as a VARCHAR2
character string. This presents problems, particularly when using a SUBSTRING function to obtain a string
to store in the database. This string will be padded with blanks by Oracle if it is not as long as the
SUBSTRING definition. This is not a problem when running an application against a Progress database. As
an example, if we use the SUBSTRING(4,4) function on the character string YELLOW, Progress will
return the three character string LOW. Oracle however, will return the four character string LOW
(note one trailing blank space).
As a general rule, it is good practice to trim trailing blanks from character strings before assigning them to
the database.

December, 1998

Page 7

Building High Performance Applications with the Progress Oracle DataServer

Progress To Oracle Database Conversion Utility


Progress provides a suite of utilities to convert a Progress database to an equivalent Oracle7 or Oracle8
database. You should understand how these utilities work before using them. The utilities will create
RECID columns and shadow fields for case-insensitive indexes when necessary, convert arrays in the
Progress database to multiple fields in Oracle, determine maximum field lengths for Oracle CHAR and
VARCHAR2 datatypes based on the Data Dictionary display formats from the Progress table, and more.
Please refer to the Progress Oracle DataServer Guide for more details on these utilities.
The Progress Data Dictionary provides default display masking for formatting character data, so that a
maximum length can be applied to the data being displayed (though it does not affect the data being stored
in the database). This display format in Progress is optional and has a default value of 8 characters. When
converting a Progress database to Oracle, the conversion utility will use this display format to determine a
maximum length for the variable length column in Oracle. This default is usually too small to store some
character data. In order to work around this, the DataServer will modify the SQL CREATE TABLE
statement for all fields that have a display format of 8 characters to create a maximum column length of 30
characters in Oracle. If this length is still not sufficient, the offending character string display formats can
be modified in the Data Dictionary, or the SQL code generated by the conversion utility can be manually
edited before running the SQL script to create the objects in your Oracle database.
You may also wish to take advantage of functionality provided by the Oracle database (such as tablespaces)
to determine optimal data storage and data access configurations. Please refer to your Oracle
documentation to determine how to configure data file creation and placement. In Version 9, the Progress
Oracle DataServer allows you to specify tablespace names for tables and indexes generated by the
conversion utility. Please refer to the Progress Oracle DataServer Guide for further information.
Please note that the creation of multiple fields for array representation, the addition of columns to support
case insensitive indexing, and RECID columns for scrolling demand close investigation because of limits to
the number of columns per table and the number of components per index imposed by the Oracle7
RDBMS. Appendix A contains a sample Progress 4GL program to calculate the number of columns a
Progress table would need in an equivalent Oracle table.

December, 1998

Page 8

Building High Performance Applications with the Progress Oracle DataServer

Application Design
The Progress 4GL may behave differently when accessing an Oracle database than it would when accessing
a Progress-based one. The following sections discuss these behavioral differences, how the DataServer
resolves them, and techniques that should be implemented in application design to allow for both high
performance and database independence.

Unsupported Syntax
Due to inherent differences between the Oracle and Progress RDBMSs, there are some Progress 4GL
statements and functions that do not behave as expected, or will not work with the Progress Oracle
DataServer. Please refer to the Progress Oracle DataServer Guide for the latest information on
unsupported Progress 4GL functionality.

Utilizing Oracle-Specific Functionality


In order to potentially improve performance by taking advantage of Oracle technology, the Progress Oracle
DataServer offers support for several Oracle-specific features including the following:

Stored Procedures
The Progress Oracle DataServer supports the use of Oracle PL/SQL stored procedures, stored
functions, and packages. These Oracle objects can be called directly from the Progress 4GL via
the RUN STORED-PROC command. By running stored procedures, processing is moved off
the Progress client, onto the database server machine. Stored procedures are useful in reducing
network traffic when aggregations of large numbers of records need to be performed, or when
performing mass modifications to database records.

Native Oracle SQL Syntax Support


The Progress Oracle DataServer provides a function called send-sql-statement that can be
used to send native Oracle SQL (utilizing either SQL*Plus or PL/SQL syntax) directly to the
underlying Oracle database. This may be useful in situations where functions or syntax
available to the Oracle database manager would be beneficial to the application, or when
application processing is better suited to being executed on the server. This SQL syntax will be
ignored by the Progress compiler in order to support the different Oracle SQL dialects, and as
such, the SQL string may be an arbitrary expression that can only be evaluated at run-time.
Therefore, syntax errors will not be detected until application run-time.
Please refer to the Progress Oracle DataServer Guide for more details on using the send-sqlstatement stored procedure.

Optimizer Hints
The Oracle database allows the passing of hints to the Oracle optimizer to determine (among
other things) which index to use in resolving a query. The Progress Oracle DataServer supports
the use of these index hints. In cases where performance might be improved by hinting an
index to Oracle, these hints should be used within the Progress 4GL syntax.
Please refer to the Progress Oracle DataServer Guide for more details on how to use Oracle
hints.

Transactions
The Oracle data manager handles transaction rollback and recovery through its own internal mechanisms,
however, Progress 4GL transaction scoping rules still apply.

December, 1998

Page 9

Building High Performance Applications with the Progress Oracle DataServer

In Progress, transactions end at the end of the outermost block where an update takes place. When a
transaction that updates an Oracle database ends successfully, the Progress Oracle DataServer sends a
COMMIT message to the Oracle data manger. If the transaction is interrupted, Progress sends a
ROLLBACK message to the Oracle RDBMS.
If you modify data in more than one database in a single transaction (for example, a Progress database and
an Oracle database), Progress uses a two-phase commit protocol to minimize the chance of database
corruption wherever possible. When using distributed Oracle databases, the changes to the Oracle database
are performed first using Oracles own two-phase commit protocol, then the changes to the Progress
database are committed.
Please refer to the Progress Oracle DataServer Guide for more details on using the two-phase commit
protocol.

Stored Procedures and Transaction Scoping


When Oracle stored procedures are called from a Progress procedure, different transaction
scoping rules apply. A database modification made through an Oracle stored procedure in a
subtransaction will not be rolled back if the main Progress transaction in which it is run is
undone. For example, if you are updating records and run a stored procedure in the middle of
the transaction, and then issue a ROLLBACK statement, the ROLLBACK will not affect any
of the operations executed by the stored procedure, as the stored procedure has its own
transaction scope within the Oracle database management system.

Constraint Violations / Trigger Execution


The Oracle RDBMS will ensure that any Oracle database constraints and database triggers will
not be executed until the record is written to the database. If this isnt handled before the
transaction end (i.e. using either the VALIDATE or RELEASE Progress 4GL statements), the
user may not be able to gain control of the user interface.
If a user attempts to insert or update a column in a unique index, other users attempting to
perform a similar update may have to wait until the first user either commits the transaction (in
which case, the second user will receive a constraint violation), or rolls back the changes (in
which case the second user will proceed). This is native Oracle RDBMS behavior, and cannot
be circumvented.

Triggers
If applications outside of the Progress environment are accessing the same Oracle tables as a Progressbased application through the Progress Oracle DataServer, then these native applications will only be
affected by Oracles database triggers. If implemented, Progress client triggers will fire in addition to these
Oracle database triggers only for Progress-based applications. If there are both Progress client triggers and
Oracle database triggers, the Progress client triggers will fire before the Oracle database triggers.
You can restrict Progress client triggers from executing when using Oracle databases with the DBTYPE
function. For example, the following code would only fire a trigger when running on a Progress database:
IF DBTYPE(dbname) = "PROGRESS" THEN DO:
{triggers.i}
END.

Record Locking
Both the Progress and Oracle databases implement record level locks. However, there are differences in the
types of locks that can be taken out on a record. These differences are described in more detail below. In
general, it is best to use optimistic record locking to mask these differences. Optimistic locking involves
reading records with NO-LOCK, and re-reading them again at update time with an exclusive lock. This will
mean the records are locked for the shortest time possible.
December, 1998

Page 10

Building High Performance Applications with the Progress Oracle DataServer

No SHARE-LOCK Support in Oracle


The Progress RDBMS supports the concept of a SHARE-LOCK that is not directly available
in the Oracle database manager. If you are using SHARE-LOCKs within your application,
Progress cannot guarantee that a record in your Oracle database is actually locked at all. You
should implement optimistic locking techniques to reduce data concurrency problems. Specify
NO-LOCK on record reads wherever possible, as this gives the most scope for internal
optimization and allows you to take advantage of field lists in Version 8 and above of the
Progress Oracle DataServer. At time of record update, re-read the record with an
EXCLUSIVE-LOCK, and if the two record values are the same, you can proceed to update the
record.
If you need to use an EXCLUSIVE-LOCK, you should hold the lock for as short a time as
possible to reduce locking contention.
The following 4GL code illustrates an example of optimistic locking performed manually
within an application.
DEFINE TEMP-TABLE changecust LIKE customer.
FIND FIRST customer /* add WHERE criteria here */.
IF AVAILABLE customer
THEN DO:
/* copy the info to a work area */
BUFFER-COPY customer TO changecust NO-ERROR.
/* All update processing should occur to
changecust, not customer. Then, at commit
time, re-read the record. */
FIND CURRENT customer EXCLUSIVE-LOCK.
/* Compare to the customer value before any
changes were made. */
IF CURRENT-CHANGED customer
THEN DO:
MESSAGE "Record changed by another user.".
UNDO, RETRY.
END.
ELSE BUFFER-COPY changecust TO customer.
END.

Please refer to the Progress Oracle DataServer Guide for more details on locking techniques.

Automatic Optimistic Locking Support


The Progress Oracle DataServer does not perform optimistic locking by default. With Version
9 of the Progress Oracle DataServer, a new DataServer startup parameter (-Dsrv optimistic) is
available to force the DataServer to use optimistic locking as the default when modifying
records.

Cursor Repositioning
Progress uses cursors to keep track of where it is within a table. A cursor is like a pointer to consecutive
records in a table. For example, Progress uses cursors when it processes statements that return a set of
records (such as the FOR EACH or OPEN QUERY statements). Progress maintains cursor positioning
across queries. The Progress Oracle DataServer supports this behavior for tables in Oracle that have a
unique index on a mandatory integer column or tables that contain the PROGRESS_RECID column.

December, 1998

Page 11

Building High Performance Applications with the Progress Oracle DataServer

When a FIND FIRST/LAST statement is issued, Oracle builds a result set that might include every record
in a table. Performance will improve if the statement is qualified with a WHERE clause to reduce the size
of the result set (however this still will not perform as well as a FOR EACH or OPEN QUERY statement).
Cursor repositioning behaves with the Progress Oracle DataServer as it does with Progress databases,
except when an Oracle database fails to find a record. In this case, the cursor in a Progress database is
located after the last record that was read. In the Oracle database, a failed search does not affect the cursor
if a single index is used.
For example, assume a result is made up of customer records 1, 2, 3, 4 and 5, and the cursor is positioned at
the last record (i.e. customer number 5).

5
cursor

If a FIND NEXT customer statement is issued (which uses a single index), the cursor moves as follows:
Progress Database:

Oracle Database:

1
cursor

5
cursor
(unchanged)

Regardless of which data source is used, the Progress 4GL functionality behaves consistently when this
occurs. The following statement, for example:
IF AVAILABLE customer
THEN DISPLAY customer.
ELSE MESSAGE "No customer record found".

will display the message No customer record found in each of the above situations, regardless of where
the cursor is positioned.

RECIDs and ROWIDs


The Progress Oracle DataServer will support RECID functionality in an Oracle database through the use of
an additional unique indexed integer column on the table (often called PROGRESS_RECID). These
additional columns also require indexes and sequences to populate them.
A far better strategy for Progress-based applications (Version 8 and above), is to use the ROWID function.
The ROWID function performs in a more consistent manner across Progress and Oracle databases, as well
as eliminating the need for a PROGRESS_RECID column (although it will use it if one is available). Note,
however, that the ROWID function causes a newly created record to be written to the Oracle database
earlier than it would to a Progress database. If you do not assign values to all fields that are defined as
mandatory in Oracle for a record, the ROWID function will fail.
By default, the Progress Oracle DataServer designates a column to support the ROWID function. It
evaluates the indexes available for a table and selects one in the following order:
1.

PROGRESS_RECID column
If a PROGRESS_RECID column is selected, then both the RECID and
ROWID Progress 4GL functions can be used in a Progress 4GL program.

December, 1998

Page 12

Building High Performance Applications with the Progress Oracle DataServer

2.

Unique index on a single, mandatory, NUMBER column with precision <10 or undefined and
scale 0 or undefined
If a unique indexed column is selected, then both the RECID and ROWID
Progress 4GL functions can be used in a Progress 4GL program.

3.

Native (Oracle) ROWID


If a native Oracle ROWID column is selected, then only the ROWID
Progress 4GL function can be used in a Progress 4GL program (the RECID
function will not work).

The native Oracle ROWID typically provides the fastest access to a record. However, the native ROWID
does not support the Progress FIND PREV/LAST statement or cursor repositioning.

Record Scoping / Availability


When using a Progress RDBMS a new record becomes available to users as soon as it is supplied with
index information. This differs from the Oracle RDBMS, where a record is not written to the database (and
therefore not available to users) until the end of the record scope. This difference can be worked around by
forcing the record to be written to disk as soon as the index information is supplied. This can be done by
using either the RELEASE or the VALIDATE statement. To illustrate this behavior, lets look at the
following piece of Progress 4GL code.
DEFINE BUFFER xcust FOR cust.
CREATE cust.
cust-num = 111.
FIND xcust WHERE xcust.cust-num = 111.
DISPLAY xcust.

When the previous example is run against a Progress database, customer number 111 will be displayed.
The Progress Oracle DataServer, however, will return an error, as the new record does not get written back
to the Oracle database until the end of the record scope (in this case after the DISPLAY xcust statement).
This problem can be corrected in the following manner:
DEFINE BUFFER xcust FOR customer.
CREATE customer.
cust-num = 111.
VALIDATE customer. /* or RELEASE customer. */
FIND xcust WHERE xcust.cust-num = 111.
DISPLAY xcust.

If you are using the NO-ERROR option and the SESSION-STATUS:ERROR function to do your own
error handling, you should use the VALIDATE statement after you have created or updated the record.
This will enable you to trap and handle errors returned from the underlying data manager. To execute on a
Progress database, the previous code might be written as follows:
DEFINE BUFFER xcust FOR customer.
CREATE customer.
ASSIGN cust-num = 111 NO-ERROR.
IF ERROR-STATUS:ERROR
THEN DO:
MESSAGE "Error Creating Record".
END.
ELSE DO:
FIND xcust WHERE xcust.cust-num = 111.
DISPLAY xcust.
END.

December, 1998

Page 13

Building High Performance Applications with the Progress Oracle DataServer

If a record with a cust-num of 111 already exists in the database, the Progress database will return the
Error Creating Record message, otherwise the record is created as per requested, and displayed from the
xcust buffer. However, when using the Progress Oracle DataServer, the customer record will not be visible
in the xcust buffer, as the record will not be written back to the Oracle database until the end of this
procedure. In order to emulate the behavior expected of a Progress database, the procedure can be modified
as follows to run against Oracle:
DEFINE BUFFER xcust FOR customer.
CREATE customer.
ASSIGN customer.cust-num = 111 NO-ERROR.
VALIDATE customer NO-ERROR.
IF ERROR-STATUS:ERROR
THEN DO:
MESSAGE "Error Creating Record".
END.
ELSE DO:
FIND xcust WHERE xcust.cust-num = 111.
DISPLAY xcust.
END.

The VALIDATE statement forces the record to be written to the Oracle database immediately. The NOERROR option ensures that user-defined error processing is invoked. The RELEASE customer NOERROR statement can also be used here, but it has the side effect of deleting the record from the client
buffers. The application would have to refetch the record from the database if it needs to access it again.

Ordering of Records
The Progress 4GLs advanced data retrieval statements, FIND <next> <prev> <first> <last> table-name
and FOR EACH table-name, coupled with the Progress RDBMS, guarantee that records are returned in a
specific order to the client. There may be instances where the Oracle database manager returns an
inconsistent sort order. If your application depends on sorted data, you should always explicitly specify
desired sort order and index criteria in your Progress 4GL statement. This can create performance
overhead, so it should only be used when the sort order is critical.

Query Tuning
The Progress Oracle DataServer provides several features to application developers to fine-tune queries to
be sent to Oracle. Further details on all the following options can be found in the Progress Oracle
DataServer Guide.

Field Lists
A feature introduced in the Version 8 Progress Oracle DataServer is the option of specifying
field lists for a query. This allows the Oracle database manager to only send back to the client
those fields of the record that were requested in the query (rather than every column in the
record). This can dramatically decrease the amount of network traffic in a client/server
environment, when records are read. It can also improve performance (to a lesser extent) in
host-based processing environments.
Field lists will only work with FOR EACH or OPEN QUERY statements. In order to take
advantage of these performance improvements, it is recommended that all FIND statements be
converted to equivalent FOR EACH or OPEN QUERY statements wherever possible.

Lookahead Cursors
The Progress Oracle DataServer caches results sets from the Oracle database to enhance
performance. It caches as much data as fits in its allocated cache size. Depending on what kind
of cursor a query is using the DataServer caches row identifiers or entire records:

December, 1998

Page 14

Building High Performance Applications with the Progress Oracle DataServer

Standard cursors The DataServer caches row identifiers for the results set. When a
record needs to be read from the results set, its row identifier is retrieved from the cache
and a new database query is generated to access the entire record.
Lookahead cursors The DataServer caches complete records (or partial records as
specified by a field list). Lookahead cursors fetch as many records as can fit in the
allocated cache, limiting the number of database accesses, and thereby improving
performance. When a record is required, its values are simply retrieved from the cache.
This can lead to data consistency problems if a records value in the database was changed
by another user after a lookahead cursor was used to read its value.
Using lookahead cursors results in behavior that is different from Progress because they do not
see any changes made to the records in the cache. Specify QUERY-TUNING NOLOOKAHEAD for behavior that is consistent with Progress (but be aware that performance
may suffer as a consequence).

Progress 4GL vs. SQL


The Progress Oracle DataServer allows you to use different approaches for querying an Oracle
database. Your application might be able to take advantage of these approaches depending on
the kind of query you are writing and the kind of data you are accessing. These approaches are:
Progress 4GL The DataServer generates optimal PL/SQL for DEFINE QUERY and
FOR EACH statements, but you can use the QUERY-TUNING option to customize the
queries that the DataServer passes to Oracle.
Progress SQL SELECT When you use a SQL SELECT statement in a Progress
procedure, the DataServer passes the SQL directly to Oracle. This approach can improve
performance, especially when counting records, and allows you to access certain types of
data more effectively, such as aggregates.
Oracle PL/SQL or SQL*Plus If you want to use specialized query syntax supported
only by Oracle's PL/SQL or SQL*Plus, you can use RUN-STORED-PROC send-sqlstatement to send the syntax to Oracle.
When retrieving a large number of records using a FOR EACH NO-LOCK or OPEN
QUERY statement, best performance is obtained by using the lookahead cursor and field list
options.
Progress/SQL SELECT statements are best for more complex queries (those with subqueries,
GROUP BY or HAVING clauses) and queries that perform aggregate functions. These
Progress/SQL SELECT statements are passed directly to the data manager using Progress
SENDSQL functionality on the server. (For the remainder of this document, this technique is termed
SQL SELECT pass-through.)
In Progress Version 8.2B and higher, SQL SELECT pass-through also makes use of Oracle
bind variables so the SQL code generated by the DataServer is reusable, thereby reducing
processing time. The SQL that is sent to Oracle using the send-sql-statement stored procedure
does not use bind variables.
FOR EACH and OPEN QUERY statements (when used with the NO-LOCK and
LOOKAHEAD options) tend to perform better than the send-sql-statement stored procedure,
because they use array fetches to minimize the number of accesses to the database. Also, if
Progress networking is used, the DataServer will pack multiple rows per network message.
The Progress send-sql-statement stored procedure and Progress/SQL SELECT pass-through
statements use a single row buffer to fetch records into, and a single result row per network
message. The send-sql-statement stored procedure is also useful for massive updates, provided
they do not occur in a subtransaction that needs to be rolled back.

December, 1998

Page 15

Building High Performance Applications with the Progress Oracle DataServer

Join-By-SQLDB
Another query tuning option introduced in Progress Version 8 is the ability to direct the Oracle
database manager to perform a querys join on the server. This is preferable to the default
action of sending two result sets down to the client (very costly in a networked environment)
and having that client (often a less powerful machine than the server) perform the join.
This JOIN-BY-SQLDB option (in either a FOR EACH or OPEN QUERY statement) should
perform better than a send-sql-statement stored procedure join for three major reasons:
1. JOIN-BY-SQLDB will do an array fetch.
2. JOIN-BY-SQLDB will ship multiple result rows in a single network message.
3. JOIN-BY-SQLDB will eliminate redundant information.
For example, consider a customer table with exactly 2 customers, each with 10,000 orders, and
the following 4GL code:
FOR EACH customer, EACH order OF customer:
. . . .
END.

If the server performs the join, the client will receive the first customer, all of their 10,000
order rows, and then the second customer and their 10,000 order rows. If this join is performed
with a send-sql-statement stored procedure (or Progress/SQL SELECT pass-through), 20,000
result rows will be shipped to the client. Each of the first 10,000 result rows will contain all of
the columns from the customer table with the values for the first customer duplicated 10,000
times. This will be followed by a similar arrangement for the second customer and their orders.

Error Messaging
Many of Oracles error messages do not provide clear descriptions of the problems being encountered. If
your application will run against both Progress and Oracle RDBMSs, you may want to consider handling
error messages through Progress to provide consistent behavior across both Progress and Oracle databases.

Distributed and Batch Processing with an Oracle Database


Progress 4GL batch programs or Progress AppServer programs have the same restrictions that apply to
interactive client Progress 4GL programs noted throughout this document. If any batch programs are to
perform mass updates or deletes, you may wish to investigate the use of stored procedures as this will
improve performance (due to reduced messaging). If any batch processing is to occur, careful consideration
must be given to the DataServer configuration, as the Progress Oracle DataServer would be required on the
batch or application server, instead of the client machine.

Mass Database Modifications


Due to the amount of network traffic that is involved in ensuring compatibility with the Progress Oracle
DataServer, mass modifications (e.g. repeated inserts, updates or deletes) of an Oracle database are best
suited to being executed from within an Oracle stored procedure (using the Progress send-sql-statement
stored procedure to execute it).

Oracle Query Resolution


All query resolution will be performed by the Oracle optimizer. The Progress Oracle DataServer will
generate index hints on queries where appropriate before sending them to Oracle, however, care should be
taken when selecting the Oracle optimization method, as all hints will be ignored when using Oracles rulebased query optimization.

December, 1998

Page 16

Building High Performance Applications with the Progress Oracle DataServer

INDEXED-REPOSITION Support
The INDEXED-REPOSITION option of the OPEN QUERY statement is only supported by Version 9 (and
above) of the Progress Oracle DataServer. In order for applications accessing an Oracle database to use this
functionality, the query must be defined as SCROLLING, and the table must support the ROWID function.
The INDEXED-REPOSITION phrase is not supported on a view that does not have a selectable ROWID.
Refer to Section 5.7 for more information on using ROWIDs with the Progress Oracle DataServer.

December, 1998

Page 17

Building High Performance Applications with the Progress Oracle DataServer

Deployment Considerations
Once an application has been created with the Progress Oracle DataServer, there are several deployment
factors that can affect the application's performance and the DataServer's administration. The following
sections discuss these different options and how they influence the application execution environment.

Building Progress Executables


The UNIX installations of the Progress Oracle DataServer (prior to Version 9) require you to build a set of
new Progress executables to incorporate the appropriate Oracle libraries. The exact executables that need to
be built depend upon the configuration required. As of Version 9, the Progress Oracle DataServer provides
pre-built executables (one set for Oracle7, one for Oracle8) linking in Oracle objects installed in shared
libraries, no longer requiring that the executables be built manually on platforms where Oracle supplies a
shared library.
Please refer to the Progress Oracle DataServer Guide for additional information on determining when new
executables need to be created.

Schema Holders
The schema holder contains information about the data definitions of an Oracle database. This information
includes a description of Oracles structure, the tables, the fields within the tables, and the indexes. The
schema holder contains no user-application data. The Progress Oracle DataServer accesses the schema
holder only when it compiles procedures and at the beginning of a run-time session when loading data
definitions into memory.
As a schema holder is normally run in read-only mode, concurrent access to it by multiple users is not
necessary. The schema holder may also be able to store Progress objects required by applications. For
example, the RBREPORT table accessed by the Progress Report Builder could be stored within the schema
holder, without requiring a separate database connection. (In this instance, however, the schema holder
cannot be connected to in read-only mode.)
For performance reasons, schema holders are best placed locally on the client rather than centrally on the
server (although this difference is much less noticeable when using a fast Ethernet connection as opposed
to 10BaseT configuration).
If a schema holder is desired on a server (for maintenance reasons), it is possible to use the cache database
connection parameter to keep a cached copy of the schema holder on the clients local disk, for faster
connection times. Refer to the Progress System Administration Guide for further details on the cache
parameter.

Oracle Database Changes and the Schema Holder


If the structure of the underlying Oracle database schema changes in any way (for example, adding a table
or view, or modifying the table by adding a new column), the Progress schema holder must be updated to
reflect those changes.
Utilities are provided with the Progress Oracle DataServer to verify that the schemas for the Oracle
database and the schema holder match, or to automatically update them if they dont. Refer to the Progress
Oracle DataServer Guide for more details on these utilities.

Incremental Schema Difference File


As of Progress Version 9, the Progress Oracle DataServer offers a utility for converting a Progress .df file
(containing incremental changes made to a Progress schema) into a .sql file. This .sql file contains these
changes in a format suitable for execution against an Oracle database. This .sql file can then be run against
the Oracle tables to replicate the schema changes. This utility can also optionally create a delta.df file that
December, 1998

Page 18

Building High Performance Applications with the Progress Oracle DataServer

can be applied directly to the existing schema holder. This will allow all formatting information previously
applied to the schema holder to be retained for unaffected objects.

Code Recompilation Due to Schema Changes


Often, a central database is accessed by more than one application. These applications will typically
share the data in the database tables, without concern for other applications. Oracles concurrency
techniques ensure that consistency is maintained at the data level, regardless of the application. However,
there may be situations where one application requires changes to be made to an existing table structure
that is referenced by other applications (for example, adding, deleting or renaming columns). Often, in a
Progress environment, such data object changes will force recompilation of all Progress code accessing this
object. This is due to a different CRC (cyclic redundancy check) value being calculated on that object after
the change. This recompilation phase is an inconvenience, especially when such changes were caused by a
different application and do not affect the application requiring recompilation.
This issue can be avoided with the Oracle database with the use of Oracle views. By creating a view of the
table containing only those columns required by the application, any changes made to the underlying table,
as long as they do not affect the views definition, will be transparent to the application. As the view is
based on a single table, all normal Progress functionality can be performed on this view as though it were
the original table. Assume the following customer table definition as an example:
cust_num
(integer)
1
2
.
.

name
(char)
Lift Line Skiing
Sails Afloat
.
.

credit_limit
(decimal)
5,000.00
2,300.00
.
.

sales_rep
(char)
BBB
ARP
.
.

If we create a view (called, for example, v_customer), based on the above customer table, and defined as
the following:
cust_num
(integer)

name
(char)

credit_limit
(decimal)

sales_rep
(char)

our application can now access the data through this view as though it were the original table (which,
essentially, it is). To mask the differences in object naming (the tables name is customer, and the view,
v_customer), we can change the name of the view in the Progress schema holder to customer. The mapping
to the view remains the same, and our application will not need to be changed.
What happens when a third-party application requires a change to the structure of our base customer table?
The answer would depend on the types of changes occurring. The following chart specifies the types of
changes possible on a table structure, and whether or not the application needs recompilation under those
circumstances.

December, 1998

Page 19

Building High Performance Applications with the Progress Oracle DataServer

Change Description
Adding a column
Adding a column
Dropping a column
Dropping a column
Adding an index
Adding an index
Dropping an index
Dropping an index

Referenced in
View?
No
Yes
No
Yes
No
Yes
No
Yes

Recompilation
Needed?
No
Yes
No
Yes
No
No
No
No

Creating a view does not affect indexing and query resolution. Indexes behave just as they would if you
were accessing the table directly.
Please note that if a column is added to the underlying table (and this column is not reflected in the view),
and you attempt to undo the delete of a row in this view from within a subtransaction, the undo will fail.
The Progress Oracle DataServer will generate an error and rollback the entire transaction.
Refer to the Progress Oracle DataServer Guide for more details on using Oracle views.

Startup Parameters
You should be aware of, and test your applications with, the DataServer (-Dsrv) connection parameter and
its various options. The following options are available for use with the Progress Oracle DataServer:
qt_bind_where / qt_no_bind_where
Specifies whether the DataServer uses Oracle bind variables for values in WHERE clauses.
qt_cache_size
Specifies the size of the cache (in bytes or records) for information used by lookahead or
standard cursors.
qt_debug / qt_no_debug
Specifies whether the DataServer should print debugging information that it generates for the
query to the dataserv.lg file.
qt_lookahead / qt_no_lookahead
Specifies whether the DataServer uses lookahead or standard cursors.
optimistic
Specifies whether the DataServer is to use optimistic locking techniques as the default when
locking records.
skip-schema-check
Specifies the DataServer is to bypass verifying schema definitions match between Oracle
database and the schema holder.
Refer to the Progress Oracle DataServer Guide for more details on these parameters.

Migrating Multiple Progress Databases


Additional consideration should be given if your current application requires multiple Progress databases.
You must determine how you will handle this in Oracle. Will you have one large database or will you keep
your existing database architecture? One large Oracle database may result in conflicts over tables and/or

December, 1998

Page 20

Building High Performance Applications with the Progress Oracle DataServer

fields with a common naming convention. Having many Oracle databases requires extra processing
resources, as well as the use of SQL*Net or Net8 for connectivity.

Progress Runtime Licenses


The Progress Oracle DataServer is available as a runtime only license. A Progress client license is
necessary if the application is on a machine remote to the DataServer. However there are a few issues that
must be considered in a runtime environment.

Database Conversion Utilities


The Progress to Oracle Database Conversion Utility is not immediately available with the
runtime version of the Progress Oracle DataServer. This utility is provided in encrypted source
code format that can only be executed when the client is started with the -rx startup option.
Please refer to the Progress System Administration Reference for more information on the -rx
client startup option.

DataServer and Database Administration Utilities


The utilities generally used for DataServer administration under the Data Administration or
Data Dictionary tools will not be immediately available in a run-time environment. These
utilities are provided in encrypted source code format to avoid end-users inadvertently
modifying the database. To view these utilities with a run-time license, start up the client with
the -rx option.
Please refer to the Progress System Administration Reference for more information on the -rx
client startup option.

December, 1998

Page 21

Building High Performance Applications with the Progress Oracle DataServer

Troubleshooting and Performance Tuning


The Progress Oracle DataServer provides several features and utilities to allow application developers to
successfully debug programs and fine-tune application execution.
The following sections outline these utilities and enhancements, and how they can be used in application
development and deployment environments.

Query/Browse Performance
The DEFINE BROWSE statement relies on a unique record identifier for forward and backward scrolling,
hence a valid ROWID or RECID should be made available for that table.

Version 7 Progress Oracle DataServer Performance


The largest area of concern surrounding performance involves querying large sets of data. A
GET LAST QUERY statement will cause a complete set of RECIDs to be gathered before
repositioning the query at the last record (Note: this is no different than what happens with a
Progress database today). Depending on the situation it can be faster to reopen the query in
reverse order.
Another technique would be to obtain the ROWID of the last row by using a FIND statement,
and then repositioning the query to that ROWID. Regardless of the technique used, it is
important that all browsers be tested thoroughly.

Version 8 Progress Oracle DataServer Enhancements


Progress Version 8 introduced tremendous performance enhancements specifically designed to
address performance-related concerns. These enhancements include Field Lists and Lookahead
Cursors which are described in more detail in the Application Design section of this
whitepaper.

Version 9 Progress Oracle DataServer Enhancements


Progress Version 9 has improved performance of the DataServer by adding features such as
optimistic locking, skip schema check and INDEXED-REPOSITION support. Each of these
are described in more detail below, and in the Application Design section of this whitepaper.

Skipping Schema Verification


When executing .r-code, the Progress Oracle DataServer checks the data definitions of the Oracle database
to make sure they match the schema definitions in the schema holder. If they do not match, the DataServer
returns an error. Unmatched definitions can result in the corruption of your Oracle database. However,
verifying the definitions is time consuming in a product scenario. The -Dsrv skip-schema-check startup
parameter bypasses the checking of schema definitions. Use this parameter with caution, as it will not
detect discrepancies between the schema in the schema holder and the data definitions in the Oracle
database. If it continues to process queries, inserts, and deletions, the Oracle database might become
corrupted.

Debugging DataServer Applications


The Version 8 Progress Oracle DataServer introduced the ability to print debugging information about
queries made to Oracle generated by the DataServer. This information is captured in the dataserv.lg file.
Seven different levels of debugging information can be captured (along with the default of no information).

December, 1998

Page 22

Building High Performance Applications with the Progress Oracle DataServer

Debug SQL
This option prints out the SQL code that the DataServer executes against the Oracle DBMS.
For example, the following 4GL code:
FIND state "NH" NO-ERROR.
FOR EACH customer FIELDS (name) NO-LOCK,
EACH order fields () OF customer NO-LOCK:
END.

will generate the following qt_debug,SQL information in the dataserv.lg file:


06:41:39 OCI call oparse <2>
sqlcrc = 18586
06:41:39 SELECT /*+ INDEX_ASC(T0 STATE##STATE) */ progress_recid
FROM SPORTS.STATE T0 WHERE (U##STATE = upper(:1))
order by U##STATE
06:41:39 OCI call oparse <3>
sqlcrc = 16402
06:41:39 SELECT T0.progress_recid unique_int_0, T0.CUST_NUM, T0.U##NAME,
T0.NAME,T1.progress_recid unique_int_1, T1.CUST_NUM
FROM SPORTS.CUSTOMER T0, SPORTS.ORDER_ T1
WHERE (T1.CUST_NUM = T0.CUST_NUM)

Debug Extended
This option prints out additional information to the DEBUG SQL option, such as the execution
of cursors, and array processing statistics.
The following 4GL program (as above):
FIND state "NH" NO-ERROR.
FOR EACH customer FIELDS (name) NO-LOCK,
EACH order fields () OF customer NO-LOCK:
END.

will produce the following output when used with qt_debug,extended:


06:41:44 OCI call oopen <5> cc = 1
06:41:44 OCI call oparse <5>
sqlcrc = 18586
06:41:44 SELECT /*+ INDEX_ASC(T0 STATE##STATE) */ progress_recid
FROM SPORTS.STATE T0 WHERE (U##STATE = upper(:1)) order by U##STATE
06:41:44 OCI call oexfet <5>
06:41:44
omru <5>
06:41:44 OCI call oopen <6> cc = 2
06:41:44 OCI call oparse <6>
sqlcrc = 16402
06:41:44 SELECT T0.progress_recid unique_int_0,T0.CUST_NUM,T0.U##NAME,T0.NAME,
T1.progress_recid unique_int_1, T1.CUST_NUM FROM SPORTS.CUSTOMER T0,
SPORTS.ORDER_ T1 WHERE (T1.CUST_NUM = T0.CUST_NUM)
06:41:44 OCI call oexfet <6>
06:41:45
omru <6>
06:41:45
omru <6>
06:41:45
Cursor <6> Rows processed 207
06:41:45
Number of array fetches 3
06:41:45
Number of rows fetched 207
06:41:45
Number of array rows
78
06:41:45
Number of array columns 6
06:41:45
Number of tables
2
06:41:45
Space for one row
104
06:41:45
Requested cache size
8192
06:41:45
Actual cache size used 8112
06:41:45 OCI call oclose <6> cc = 3
06:41:45
06:41:45
Cursor <5> Rows processed 0
06:41:45 OCI call oclose <5> cc = 2

December, 1998

Page 23

Building High Performance Applications with the Progress Oracle DataServer

Debug Cursor
This option (available with the Version 9 Progress Oracle DataServer, and as DEBUG 18835
with the Version 8.3 Progress Oracle DataServer only) prints out the SQL generated by the
DataServer, along with detailed information about cursor usage (such as opening and closing
of cursors).
The following 4GL program (as above):
FIND state "NH" NO-ERROR.
FOR EACH customer FIELDS (name) NO-LOCK,
EACH order fields () OF customer NO-LOCK:
END.

will produce the following output when used with qt_debug,cursor:


06:41:46 OCI call oopen <8> cc = 1
06:41:46 OCI call oparse <8>
sqlcrc = 18586
06:41:46 SELECT /*+ INDEX_ASC(T0 STATE##STATE) */ progress_recid
FROM SPORTS.STATE T0 WHERE (U##STATE = upper(:1)) order by U##STATE
06:41:46 OCI call oexfet <8>
06:41:46 OCI retr oexfet <8> rc = 1403
06:41:46
omru <8>
06:41:46 OCI call oopen <9> cc = 2
06:41:46 OCI call oparse <9>
sqlcrc = 16402
06:41:46 SELECT T0.progress_recid unique_int_0, T0.CUST_NUM, T0.U##NAME,
T0.NAME, T1.progress_recid unique_int_1, T1.CUST_NUM
FROM SPORTS.CUSTOMER T0, SPORTS.ORDER_ T1 WHERE (T1.CUST_NUM =
T0.CUST_NUM)
06:41:46 OCI call oexfet <9>
06:41:47
omru <9>
06:41:47
omru <9>
06:41:47
Cursor <9> oparse: 1
(0 kyr)
06:41:47
Cursor <9> oexec : 0
(0 kyr)
06:41:47
Cursor <9> oexfet: 1
(0 kyr)
06:41:47
Cursor <9> ofetch: 0
(0 kyr)
06:41:47
Cursor <9> ofen : 2
(0 kyr)
06:41:47
Cursor <9> obnd* : 0
(0 kyr)
06:41:47
Cursor <9> odefin: 6
(0 kyr)
06:41:47
06:41:47
Cursor <9> Rows processed 207
06:41:47
Number of array fetches 3
06:41:47
Number of rows fetched 207
06:41:47
Number of array rows
78
06:41:47
Number of array columns 6
06:41:47
Number of tables
2
06:41:47
Space for one row
104
06:41:47
Requested cache size
8192
06:41:47
Actual cache size used 8112
06:41:47 OCI call oclose <9> cc = 3
06:41:47
Cursor <8> oparse: 1
(0 kyr)
06:41:47
Cursor <8> oexec : 0
(0 kyr)
06:41:47
Cursor <8> oexfet: 1
(0 kyr)
06:41:47
Cursor <8> ofetch: 0
(0 kyr)
06:41:47
Cursor <8> ofen : 0
(0 kyr)
06:41:47
Cursor <8> obnd* : 1
(0 kyr)
06:41:47
Cursor <8> odefin: 1
(0 kyr)
06:41:47

December, 1998

Page 24

Building High Performance Applications with the Progress Oracle DataServer

06:41:47
06:41:47
06:41:47
06:41:47
06:41:47
06:41:47
06:41:47
06:41:47
06:41:47
06:41:47

Cursor
OCI call
OCI call
OCI call
OCI call
OCI call
OCI call
OCI call
OCI call
OCI call

<8> Rows processed 0


oclose <8> cc = 2
oexec : 2
odefin: 7
oopen : 3
oclose: 2
obndrn: 1
oparse: 4
oexfet: 2
ofen : 2

Debug Databind
This option (available with the Version 9 Progress Oracle DataServer, and as DEBUG 1029
with the Version 8.3 Progress Oracle DataServer only) prints out the SQL generated by the
DataServer, along with information about OCI bind variables and parameters passed to Oracle.
The following 4GL program (as above):
FIND state "NH" NO-ERROR.
FOR EACH customer FIELDS (name) NO-LOCK,
EACH order fields () OF customer NO-LOCK:
END.

will produce the following output when used with qt_debug,databind:


06:41:51 OCI call oparse <11> sqlcrc = 18586
06:41:51 SELECT /*+ INDEX_ASC(T0 STATE##STATE) */ progress_recid
FROM SPORTS.STATE T0 WHERE (U##STATE = upper(:1)) order by U##STATE
06:41:51 OCI call obndrn <11>
06:41:51 OCI parm obndrn <11>
06:41:51
type 5 var:1 addr: 0x6dd08c size 32 value: 'NH'
06:41:51 OCI call odefin <11>
06:41:51 OCI parm odefin <11>
06:41:51
type 3 var :1 addr: 0x6dd0e4 size 4
06:41:51 OCI call oparse <12> sqlcrc = 16402
06:41:51 SELECT T0.progress_recid unique_int_0, T0.CUST_NUM, T0.U##NAME,
T0.NAME,
T1.progress_recid unique_int_1, T1.CUST_NUM
FROM SPORTS.CUSTOMER T0,SPORTS.ORDER_ T1 WHERE (T1.CUST_NUM =
T0.CUST_NUM)
06:41:51 OCI call odefin <12>
06:41:51 OCI parm odefin <12>
06:41:51
type 3 var :1 addr: 0x6e5350 size 4
06:41:51 OCI call odefin <12>
06:41:51 OCI parm odefin <12>
06:41:51
type 5 var :2 addr: 0x6e5488 size 26
06:41:51 OCI call odefin <12>
06:41:51 OCI parm odefin <12>
06:41:51
type 5 var :3 addr: 0x6e5c74 size 22
06:41:51 OCI call odefin <12>
06:41:51 OCI parm odefin <12>
06:41:51
type 5 var :4 addr: 0x6e6328 size 22
06:41:51 OCI call odefin <12>
06:41:51 OCI parm odefin <12>
06:41:51
type 3 var :5 addr: 0x6e69dc size 4
06:41:51 OCI call odefin <12>
06:41:51 OCI parm odefin <12>
06:41:51
type 5 var :6 addr: 0x6e6b14 size 26

December, 1998

Page 25

Building High Performance Applications with the Progress Oracle DataServer

Debug Performance
This option (available with theVersion 9 Progress Oracle DataServer, and as DEBUG 55775
with the Version 8 Progress Oracle DataServer only) prints out the SQL generated by the
DataServer, along with information about cursor usage (such as opening and closing of
cursors), and timings (in mircoseconds) for Oracle SQL execution.
The following 4GL program (as above):
FIND state "NH" NO-ERROR.
FOR EACH customer FIELDS (name) NO-LOCK,
EACH order fields () OF customer NO-LOCK:
END.

will produce the following output when used with qt_debug,performance:


06:41:56 OCI call oopen <14> cc = 1
06:41:56 OCI retr oopen <14> rc = 0 (2246 us)
06:41:56 OCI call oparse <14> sqlcrc = 18586
06:41:56 SELECT /*+ INDEX_ASC(T0 STATE##STATE) */ progress_recid
FROM SPORTS.STATE T0 WHERE (U##STATE = upper(:1)) order by U##STATE
06:41:56 OCI retr oparse <14> rc = 0 (2262 us)
06:41:56 OCI call obndrn <14>
06:41:56 OCI retr obndrn <14> rc = 0 (927 us)
06:41:56 OCI call odefin <14>
06:41:56 OCI retr odefin <14> rc = 0 (769 us)
06:41:56 OCI call oexfet <14>
06:41:56 OCI retr oexfet <14> rc = 1403 (5889 us)
06:41:56
omru <14>
06:41:56 OCI call oopen <15> cc = 2
06:41:56 OCI retr oopen <15> rc = 0 (1975 us)
06:41:56 OCI call oparse <15> sqlcrc = 16402
06:41:56 SELECT T0.progress_recid
unique_int_0,T0.CUST_NUM,T0.U##NAME,T0.NAME,
T1.progress_recid unique_int_1, T1.CUST_NUM
FROM SPORTS.CUSTOMER T0,SPORTS.ORDER_ T1 WHERE (T1.CUST_NUM =
T0.CUST_NUM)
06:41:56 OCI retr oparse <15> rc = 0 (2941 us)
06:41:56 OCI call odefin <15>
06:41:56 OCI retr odefin <15> rc = 0 (883 us)
06:41:56 OCI call odefin <15>
06:41:56 OCI retr odefin <15> rc = 0 (810 us)
06:41:56 OCI call odefin <15>
06:41:56 OCI retr odefin <15> rc = 0 (769 us)
06:41:56 OCI call odefin <15>
06:41:56 OCI retr odefin <15> rc = 0 (763 us)
06:41:56 OCI call odefin <15>
06:41:56 OCI retr odefin <15> rc = 0 (767 us)
06:41:56 OCI call odefin <15>
06:41:56 OCI retr odefin <15> rc = 0 (863 us)
06:41:56 OCI call oexfet <15>
06:41:56 OCI retr oexfet <15> rc = 0 (55993 us)
06:41:56 OCI call ofen <15>
06:41:56 OCI retr ofen <15> rc = 0 (46923 us)
06:41:56 OCI call ofen <15>
06:41:56 OCI retr ofen <15> rc = 1403 (33092 us)
06:41:56
omru <15>
06:41:56
omru <15>
06:41:56
06:41:56
Cursor <15> oparse: 1
(2941 us)
06:41:56
Cursor <15> oexec : 0
(0 us)
06:41:56
Cursor <15> oexfet: 1
(55993 us)
06:41:56
Cursor <15> ofetch: 0
(0 us)
06:41:56
Cursor <15> ofen : 2
(80015 us)
06:41:56
Cursor <15> obnd* : 0
(0 us)
06:41:56
Cursor <15> odefin: 6
(4855 us)
06:41:56
06:41:56
Cursor <15> Rows processed 207

December, 1998

Page 26

Building High Performance Applications with the Progress Oracle DataServer

06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56
06:41:56

Number of array fetches 3


Number of rows fetched 207
Number of array rows
78
Number of array columns 6
Number of tables
2
Space for one row
104
Requested cache size
8192
Actual cache size used 8112
OCI call oclose <15> cc = 3
OCI retr oclose <15> rc = 0 (2405 us)
Cursor
Cursor
Cursor
Cursor
Cursor
Cursor
Cursor
Cursor
OCI call
OCI retr
OCI call
OCI call
OCI call
OCI call
OCI call
OCI call
OCI call
OCI call

<14>
<14>
<14>
<14>
<14>
<14>
<14>

oparse: 1
oexec : 0
oexfet: 1
ofetch: 0
ofen : 0
obnd* : 1
odefin: 1

(2262 us)
(0 us)
(5889 us)
(0 us)
(0 us)
(927 us)
(769 us)

<14> Rows processed 0


oclose <14> cc = 2
oclose <14> rc = 0 (2248 us)
oexec : 2
odefin: 7
oopen : 3
oclose: 2
obndrn: 1
oparse: 4
oexfet: 2
ofen : 2

Debug Summary
This option (available with the Version 9 Progress Oracle DataServer, and as DEBUG
1073797455 with the Version Progress Oracle DataServer only) gives information on cursors
and timing in summary form as a Progress data (.d) file.

Debug Verbose
This option (available with the Version 9 Progress Oracle DataServer, and as DEBUG 122879
with the Version 8.3 Progress Oracle DataServer only) prints out the SQL generated by the
DataServer, array processing statistics, information about cursor usage (such as opening and
closing of cursors), along with information about OCI bind variables and parameters passed to
Oracle, and timings (in mircoseconds) for Oracle SQL execution.
The following 4GL program (as above):
FIND state "NH" NO-ERROR.
FOR EACH customer FIELDS (name) NO-LOCK,
EACH order fields () OF customer NO-LOCK:
END.

will produce the following output when used with qt_debug,verbose:


06:42:01
06:42:01
06:42:01
06:42:01
06:42:01
06:42:01
06:42:01
06:42:01
06:42:01
06:42:01
06:42:01
06:42:01
06:42:01
06:42:01

December, 1998

<0> orgetnext
<0> new 0x0
OCI call oopen <17> cc = 1
OCI retr oopen <17> rc = 0 (1938 us)
<17> Calling idbuf_init from cursor_start
<17> new 0x0
<17> cursor_start
<17> new 0x2
Query flags <17> table 0:
WHERE COMPAT
HAS_RID IDXHINT
Query flag2 <17> table 0:
SLO_CSR
IGN_FL BIG_RNF

Page 27

Building High Performance Applications with the Progress Oracle DataServer

06:42:01 Query flag3 <17> table 0:


06:42:01
NCL_SEL
06:42:01 OCI call oparse <17> sqlcrc = 18586
06:42:01 SELECT /*+ INDEX_ASC(T0 STATE##STATE) */ progress_recid
FROM SPORTS.STATE T0 WHERE (U##STATE = upper(:1)) order by U##STATE
06:42:01 OCI retr oparse <17> rc = 0 (2232 us)
06:42:01 OCI call obndrn <17>
06:42:01 OCI parm obndrn <17>
06:42:01
type 5 var:1 addr: 0x6dd458 size 32 value: 'NH'
06:42:01 OCI retr obnrn <17> rc = 0 (2232 us)
06:42:01 OCI call odefin <17>
06:42:01 OCI parm odefin <17>
06:42:01
type 3 var :1 addr: 0x6dd4c4 size 4
06:42:01 OCI retr odefin <17> rc = 0 (2105 us)
06:42:01 OCI call oexfet <17>
06:42:01 OCI retr oexfet <17> rc = 1403 (6082 us)
06:42:01
<17> cursor_fetch OC_DIR_FORW
06:42:01
<17> NL 0x22
06:42:01
omru <17>
06:42:01 OCI call oopen <18> cc = 2
06:42:01 OCI retr oopen <18> rc = 0 (2125 us)
06:42:01 Query flags <18> table 0:
06:42:01
HAS_RID
NATDATE
06:42:01 Query flag2 <18> table 0:
06:42:01
ARY_FET ARY_MSG
06:42:01
FLD_LST JOIN_SV
BIG_RNF
06:42:01 Query flag3 <18> table 0:
06:42:01
NCL_SEL
06:42:01 Query flags <18> table 1:
06:42:01
WHERE COMPAT
06:42:01
HAS_RID
NATDATE
06:42:01 Query flag2 <18> table 1:
06:42:01
ARY_FET ARY_MSG
06:42:01
FLD_LST
BIG_RNF
06:42:01 Query flag3 <18> table 1:
06:42:01
NCL_SEL
06:42:01 OCI call oparse <18> sqlcrc = 16402
06:42:01 SELECT T0.progress_recid unique_int_0, T0.CUST_NUM, T0.U##NAME,
T0.NAME,
T1.progress_recid unique_int_1, T1.CUST_NUM
FROM SPORTS.CUSTOMER T0, SPORTS.ORDER_ T1 WHERE (T1.CUST_NUM =
T0.CUST_NUM)
06:42:01 OCI retr oparse <18> rc = 0 (2927 us)
06:42:01 OCI call odefin <18>
06:42:01 OCI parm odefin <18>
06:42:01
type 3 var :1 addr: 0x6e5b30 size 4
06:42:01 OCI retr odefin <18> rc = 0 (2222 us)
06:42:01 OCI call odefin <18>
06:42:01 OCI parm odefin <18>
06:42:01
type 5 var :2 addr: 0x6e5c68 size 26
06:42:01 OCI retr odefin <18> rc = 0 (2116 us)
06:42:01 OCI call odefin <18>
06:42:01 OCI parm odefin <18>
06:42:01
type 5 var :3 addr: 0x6e6454 size 22
06:42:01 OCI retr odefin <18> rc = 0 (2107 us)
06:42:01 OCI call odefin <18>
06:42:01 OCI parm odefin <18>
06:42:01
type 5 var :4 addr: 0x6e6b08 size 22
06:42:01 OCI retr odefin <18> rc = 0 (2104 us)
06:42:01 OCI call odefin <18>
06:42:01 OCI parm odefin <18>
06:42:01
type 3 var :5 addr: 0x6e71bc size 4
06:42:01 OCI retr odefin <18> rc = 0 (2243 us)
06:42:01 OCI call odefin <18>
06:42:01 OCI parm odefin <18>
06:42:01
type 5 var :6 addr: 0x6e72f4 size 26
06:42:01 OCI retr odefin <18> rc = 0 (2109 us)
06:42:01 OCI call oexfet <18>
06:42:01 OCI retr oexfet <18> rc = 0 (56932 us)
06:42:01 OCI call ofen <18>
06:42:01 OCI retr ofen <18> rc = 0 (47531 us)

December, 1998

Page 28

Building High Performance Applications with the Progress Oracle DataServer

06:42:01 OCI call ofen <18>


06:42:02 OCI retr ofen <18> rc = 1403 (32269 us)
06:42:02
omru <18>
06:42:02
omru <18>
06:42:02
Cursor <18> oparse: 1
(2927 us)
06:42:02
Cursor <18> oexec : 0
(0 us)
06:42:02
Cursor <18> oexfet: 1
(56932 us)
06:42:02
Cursor <18> ofetch: 0
(0 us)
06:42:02
Cursor <18> ofen : 2
(79800 us)
06:42:02
Cursor <18> obnd* : 0
(0 us)
06:42:02
Cursor <18> odefin: 6
(12901 us)
06:42:02
Cursor <18> Rows processed 207
06:42:02
Number of array fetches 3
06:42:02
Number of rows fetched 207
06:42:02
Number of array rows
78
06:42:02
Number of array columns 6
06:42:02
Number of tables
2
06:42:02
Space for one row
104
06:42:02
Requested cache size
8192
06:42:02
Actual cache size used 8112
06:42:02 OCI call oclose <18> cc = 3
06:42:02 OCI retr oclose <18> rc = 0 (2263 us)
06:42:02
Cursor <17> oparse: 1
(2232 us)
06:42:02
Cursor <17> oexec : 0
(0 us)
06:42:02
Cursor <17> oexfet: 1
(6082 us)
06:42:02
Cursor <17> ofetch: 0
(0 us)
06:42:02
Cursor <17> ofen : 0
(0 us)
06:42:02
Cursor <17> obnd* : 1
(2232 us)
06:42:02
Cursor <17> odefin: 1
(2105 us)
06:42:02
Cursor <17> Rows processed 0
06:42:02 OCI call oclose <17> cc = 2
06:42:02 OCI retr oclose <17> rc = 0 (2156 us)
06:42:02 OCI call oexec : 2
06:42:02 OCI call odefin: 7
06:42:02 OCI call oopen : 3
06:42:02 OCI call oclose: 2
06:42:02 OCI call obndrn: 1
06:42:02 OCI call oparse: 4
06:42:02 OCI call oexfet: 2
06:42:02 OCI call ofen : 2
06:42:02 (pid 25267) LOCAL Oracle USER pdb: oldbn ldb: oldbn
Logoff from dataserver db as user sports/*****. (2690)

December, 1998

Page 29

Building High Performance Applications with the Progress Oracle DataServer

Appendix A
Sample 4GL Program To Calculate The Number Of Fields Required For A Progress Table in an
Oracle Database

DEFINE VARIABLE c AS INTEGER NO-UNDO.


FOR EACH _file WHERE NOT _file._file-name BEGINS "_":
/* Initialize one field for the
progress_recid column. */
c = 1.
FOR EACH _field OF _file:
/* Add a column for every field, and a new
column for every extent within a field. */
c = c + (IF _field._extent > 0
THEN _field._extent
ELSE 1).
/* If an indexed field is case insensitive
add a column for its uppercase value. */
IF (_field._data.type = "character") AND
(NOT _field._fld-case) AND
(CAN-FIND(_index-field OF _field))
THEN c = c + 1.
END.
DISPLAY _file._file-name FORMAT "X(32)"
" table will need " c " fields"
WITH NO-LABELS.
END.

Progress and WebSpeeed are registered trademarks of Progress Software Corporation. Progress AppServer is a trademark of Progress Software
Corporation. Oracle is a registered trademark of Oracle Corporation. All other trademarks and registered trademarks, marked and not marked, are the
property of their respective owners.
Copyright 1998 Progress Software Corporation
All rights reserved.

December, 1998

Page 30

You might also like