=====================================================================
RAIMA DATABASE SERVER
VERSION 1.2.0b Release 1 RELEASE NOTES
December 12, 1994
=====================================================================
This file provides information concerning how to get help, platform/network-
specific information, and important information on features or changes in
Raima Database Server that are currently not described in the RDS
documentation.  It is important that you study this document thoroughly as
it includes information that is vital to the proper use of RDS.

This file supplements the manuals and contains the most up to date
information on Raima Database Server Version 1.2.0

NOTE: This version of RDS will install a new version of the SQL system
catalog (database SYSCAT).  You can choose whether or not to reinstall the
RDS catalog.  (The RDS system maintains a separate catalog from that used
by SQL).  If you choose to reinstall the RDS catalog, you will need to
redefine your RDS users, devices, and databases through either ADMIN or
RDSADM.  In any event, you will need to reprocess any SQL DDL files using
SDDLP.  If you do not reinstall the RDS catalog then you must specify the -
o SDDLP command line option when reprocessing your SQL DDL schema files
(see Section 6.1 below).

=====================================================================
TABLE OF CONTENTS
=====================================================================

1. INTRODUCTION               Brief overview of RDS.
                              
2. SUMMARY OF CHANGES         Summary of the changes that have been made
                              since the last release.
                              
3. PLATFORM/NETWORK INFO      Information about platform or network-
                              specific issues.
                              
4. CLIENT TRANSPORT INFO      Information about using SPX from client
                              workstations.
                              
5. GENERAL RDS INFO           Information pertaining to all uses of RDS.
                              
6. SQL                        Information on the use of RDS SQL.
                              
7. ODBC                       Information about the use of RDS SQL under
                              the Microsoft Windows ODBC driver manager.
                              
8. LOW-LEVEL RDS API          Information pertaining to use of the
                              navigational, low-level (d_) RDS application
                              programming interface functions.
                              
9. BUGS FIXED                 Descriptions of the bugs that have been fixed
                              since the last release.
                              
====================================================================
1. INTRODUCTION
====================================================================

Raima Database Server (RDS) represents the culmination of several years of
development at Raima of a high-performance, client-server-based version of
our Raima Database Manager (RDM) product.  The objectives of the
development effort were to:

 *  provide the next generation RDM that could support larger, more
     transaction-intensive multi-user, client-server database applications;
     
 *  provide the industry standard SQL database language;
     
 *  support multiple server environments including Novell NLM, OS/2, UNIX,
     and Microsoft NT; and
     
 *  provide for server-based application programming.
     
RDS is a multi-threaded database server providing advanced transaction
processing and logging capabilities supporting both roll back and roll
forward recovery.  RDS also supports true record-level locking, a large,
configurable database I/O cache, and asynchronous, "piggy-backed" file I/O.
The SQL provided in RDS is based on 1989 ANSI SQL with integrity
enhancements and the Microsoft Windows Open Database Connectivity (ODBC)
specification.

Server-based application-specific programming can be done through use of
the RDS extension module and the SQL user-defined function facilities.

The RDS system has been designed to provide the kind of performance,
extensibility, scalability, and reliability that are needed for building
production quality client-server database applications.

=====================================================================
2. SUMMARY OF CHANGES
=====================================================================

The changes made since release 1.0.1 include new SQL features that provide
for better migration of RDM applications to RDS and to allow for easier
development of combined API applications (i.e., those that use both the RDS
d_ and the SQL APIs).  The bugs that have been fixed are since the last
release are described in section 8.

Some new SQL features have been added.  These include:

     -    The c_data type and scalar function to allow for the declaration
          of C data structures in SQL DDL specifications.
     
     -    A new function library containing functions that can be used from
          an RDS d_ program to manipulate SQL-specific data types: decimal,
          date, time, and timestamp.

Also described in this README are the following SQL features that were
included in the 1.0.1 release:

     -    Improved error reporting in SDDLP
     -    Optional index support in SQL
     -    Security command logging

These features are described in detail in section 5.

A revision of the RDS documention that will include all of the new features
is in preparation and will be included in the production release.

=====================================================================
3. PLATFORM/NETWORK-SPECIFIC INFORMATION
=====================================================================
3.1 NOVELL NETWARE
------------------
3.1.1 PLEASE NOTE
-----------------
DON'T USE ^C TO STOP SERVER ON NETWARE
To shut down RDS, select the Netware console screen labeled "Raima Database
Server", and type 'q'.  Do not use the URDS script before the server has
been shut down from its own screen.

USE NETWARE CONTROL FILE SCRIPTS TO START NETWARE VERSION OF RDS
Two ".ncf" files have been provided to load and unload RDS.  Use RDS.NCF by
typing "RDS" (not "LOAD RDS") at the Netware console.  This script performs
a series of UNLOADs before loading the RDS NLMs.  A series of messages such
as "Module SDDLP not loaded" is expected.  The RDS script may be run
repeatedly.  To eliminate the RDS NLMs from memory, use URDS.NCF by typing
"URDS" at the Netware console.

3.1.2 NEW FEATURES NOT DESCRIBED IN MANUALS
-------------------------------------------
SERVER STATUS UTILITY
See the Getting Started booklet for a description of RSTAT.

3.1.3 KNOWN PROBLEMS
--------------------
NO SUPPORT FOR NETWARE 4.01
RDS will start up on a Netware 4.01, but will cause Netware to crash after
a small amount of use.  We do not advise using RDS on Netware 4.01 until a
future release of RDS.  Experiment at your own risk!

RDS.LOG MAY NOT CONTAIN FULL LOG
The server log file, RDS.LOG, will be placed into the root of the default
volume (the one on which you installed RDS).  If the server crashes for
some reason, the contents of this file may be incomplete.

NETWARE 286 MEMORY POOL ADJUSTMENTS
If you have a Netware 286 server (version 2.15) in the same network that
RDS is running, you will need to watch your memory pool 1 statistics.
Netware 286 servers have a limited amount of memory in this pool, and when
the pool is exhausted, the server can crash in an unpredictable fashion.
RDS does not use much memory in this pool; in our tests, RDS used less than
1K when we ran one server with approximately 32 clients.  However, if your
Netware 286 server is heavily used (70 or more users), or if your memory
pool is small, you should examine the network statistics to make sure that
this pool is not exhausted.

You can use the fconsole utility (provided by Novell) to examine the pool.
To do this, type "fconsole".  Then select the "statistics" and then the
"summary" menu options.  Then examine the "Dynamic Memory Pool 1" line, and
look at the Max, Peak, and Current usage columns.  If either the peak or
the current usage columns approaches the max column, you are in danger of
running out of memory.  Your Novell network administrator can usually
increase the amount of memory in this pool.  This is an absolute maximum,
and if he or she cannot increase the memory pool, then you will either need
to look at ways to reduce the load (e.g., reduce the number of users
connecting to the server, move email to another server, or move the print
server to another server), or if you cannot reduce the load, obtain another
server.  We would recommend Netware 386 because it has no such limits.

3.2 OS/2 2.1 AND NT PLATFORMS
-----------------------------
3.2.1 Please Note
-----------------

The installation chapter in the "Getting Started and Release Notes" has not
been updated to reflect the installation of this Beta.  So please regard
the information in that chapter with "a grain of salt." To install, place
Disk 1 into the floppy drive and type:

<drive>:install

3.2.2 OS/2 Specific Installation Information

SETTING THE PATH TO THE CATALOG DIRECTORY
Before you can start the server you must set an environment variable called
CATPATH to point to the catalog directory under the directory in which you
installed RDS.  For example:

     set CATPATH=c:\rds\catalog

NAMING THE SERVER IN AN LAN MANAGER OR LAN SERVER ENVIRONMENT.
The server name must be the same as the Lan Server(OS/2) node name.  For
example, to start the server if the node name is BrianS use:

     rds BrianS

To run client programs on the same platform as the server you will need to
set the environment variable LNNAME to your server name (Lan Server node
name).  For example:

     set LNNAME=BrianS

On a client on a different machine than that which the server is running
on, do not set this environment variable.  Simply reference the server
using the name provided at startup.

OS/2 2.1 COMPILER SUPPORT
This release supports the following compilers:

OS:            Client Side:             Extension Modules:
---            ----------------         ------------------
OS/2 2.1       IBM CSET++  2.01         IBM CSET++  2.01
OS/2 2.1       Borland C++ 1.00
OS/2 1.3       Microsoft C 6.00A
MSDOS          Microsoft C++ 8.0
Windows 3.1    Microsoft C++ 8.0
Windows 3.1    Borland C++ 3.1


3.2.3 NT Specific Installation Information

RDS is installed as an NT service, and, upon successful installation, it
can be controlled via the NT Service Control Manager Control Panel
(Services under Control Panel).  By doing so, the RDS server becomes
visible as an NT service throughout the NT domain. This was done in order
to make the RDS Name Service Facility work.

Additionally, RDS makes use of the NT Registry to store various pieces of
configuration information. Included in this information is the name by
which the RDS server is to be known as in the LanManager domain (limited to
8 characters).

As part of the installation process, you will be asked for this name.  The
installation program will then install the RDS server under the NT Service
Control Manager by that name.

The utility program which interfaces with the Service Control Manager and
the Registry is called RDSINST.  This program is used to both add and
delete the RDS service.

If it becomes necessary to change the name by which RDS is to be known on
the network, then it is first necessary to remove the service.  This is
done by invoking RDSINST with "remove" as the parameter:

     RDSINST remove

To reinstall the service by the new name, run RDSINST specifying the name
and the directory which contains the RDS files:

     RDSINST MyServer c:\rds

3.2.4 TCP/IP CONFIGURATION FOR RDS NAME SERVICES
In order for a TCP/IP client to connect to a server it is necessary for the
hosts and services files of both to be in sync.  In the hosts file, it is
necessary to include an entry for the name of the server with the
corresponding internet address.  Similarly, it is necessary to include an
entry in the services file for that server name with the protocol type of
"rds".

For example, suppose you have a server "srvnode" on which you wish to run
an RDS server to be known as "accting".

In the hosts file you would put an entry:

...
192.9.200.16 srvnode accting
...

In the service table you would put an entry:

...
accting         1030/rds    ## Raima Database Server
...

The entry in the services table contains the socket that clients will use
to connect to the server.  The choice of socket is arbitrary but must not
conflict with the other entries in the services table.

TCP/IP PRODUCT CONFORMANCE

The DOS and Windows RDS NCP software was built with the NetManage Chameleon
product.  In order to run a DOS client it is necessary to have installed
the Chameleon D product.  In order to build a DOS client application using
the RDS supplied client library, it is necessary to link with the NetManage
Newt TCP/IP libraries.  The Windows RDS DLL is built with Newt, but because
Newt is WINSOCK compliant, it is theoretically possible to use any vendor's
WINSOCK compliant DLL.

Finally, the NT TCP/IP DLLs are built with the Microsoft supplied libaries
and work in conjunction with the protocol stack that is delivered as part
of NT.

3.2.2 KNOWN PROBLEMS
--------------------
None.

=====================================================================
4. CLIENT TRANSPORT INFORMATION
=====================================================================
4.1 PLEASE NOTE
---------------
NOVELL NETX OR VLM SUPPORT
During installation of the RDS client, you selected NETX or VLM support.
The choice should match the network software that is installed on the
workstation.  Novell is attempting to convert its customers to use VLMs
instead of NETX, but currently both transport implementations exist.  VLMs
contain better support for Netware 4, but NETX will still run on Netware 4.

We have created two sets of files for supporting the running and building
of DOS/Windows clients with NETX or VLM.  The following files are affected
by the installation selection:
     DLL\CNCP16.DLL
     LIB\RDSCLI.LIB
     BIN\SDDLP.EXE
     BIN\DDLPROC.EXE
     BIN\RSQL.EXE
     BIN\RDSADM.EXE
     BIN\DAL.EXE
     BIN\DDLGEN.EXE
     BIN\NETTEST.EXE
In addition, we supply Netware DLLs which correspond to NETX or VLM.  If
you selected NETX, the DLLs will be:
     NWBIND.DLL, NWCONN.DLL, NWCORE.DLL, NWIPXSPX.DLL, NWMISC.DLL
If you selected VLM, the DLLs will be:
     NWCALLS.DLL, NWIPXSPX.DLL, NWLOCALE.DLL, NWNET.DLL
These are all placed into the RDS DLL subdirectory.  You may have obtained
these same DLLs from Novell as well.  They are provided in case they are
needed.

VLM UPGRADES ARE AVAILABLE FROM NOVELL
If your DOS client workstations are using NETX instead of VLM, you may be
able to convert them to use VLMs.  The required files are available from
Novell.  If you use Compuserve, find the NOVFILES forum, go to the "client
kits" subsection, and choose the VLM option.  You must download 3 files.

THE VLM NET.CFG REQUIRES AN ADDITIONAL STATEMENT
If RDS is running on Netware 3.11, the NET.CFG file that is created during
installation of the workstation VLM must include the following statement
under the "NetWare Dos Requester" section:
     directory services off

LINKING DOS APPLICATIONS REQUIRES A NETWARE SDK
When linking DOS applications with the RDS client library RDSCLI.LIB, it is
also necessary to link the network transport libraries provided in the
"NetWare C Interface for DOS."  The transport libraries for the VLM version
of the SDK are called NWCALLS.LIB and LNWIPXSP.LIB.  The transport library
for the NETX version of the SDK is called LNIT.LIB.  You must obtain these
libraries from the respective Novell SDK.

4.2 NEW FEATURES NOT DESCRIBED IN MANUALS
-----------------------------------------

4.3 KNOWN PROBLEMS
------------------
DOS/WINDOWS CLIENTS MUST ALWAYS LOGOUT
For every s_login call, there must be a s_logout call.  Because of the
network connections established by a login, failure to properly terminate
the network connections will lead to erratic behavior after you client
application has terminated.

RDS CLIENTS WILL NOT WORK WITH WINDOWS FOR WORKGROUPS AND VLM
Some incompatibilities exist between WFW and the Novell VLM software.  We
are unable to support RDS Windows clients in this environment.

RDS CLIENTS BUILD WITH VLM SDK WILL NOT RUN ON NETX WORKSTATIONS
The RDS DOS utilities build for VLM support will not locate an RDS server
if they are run on a workstation running NETX.

=====================================================================
5. GENERAL RDS INFORMATION
=====================================================================
5.1 PLEASE NOTE
---------------
None.

5.2 NEW FEATURES NOT DESCRIBED IN MANUALS
-----------------------------------------
DDLPROC OPTION TO SUPPORT CASE SENSITIVITY
The default behavior of DDLPROC is to maintain case sensitivity.  To turn
off case sensitivity, add the option "-s-" to the command line.

STARTING THE SERVER WITH A "MINIMAL" CONFIGURATION
If the catalog configuration is not operable (e.g. because the number of
cache pages is too big), the server may not be able to start.  Since the
server must be running to change the configuration, you must start the
server with an alternative "minimal" configuration.  The command-line
option is:
     rds -minimal             (for OS/2 and NT)
or:
     load server -minimal     (for Netware, in the RDS.NCF file)

The -minimal option causes the server to start with configuration
parameters that will allow the use of ADMIN or RDSADM to correct the
catalog.  After correcting the catalog configuration problem, stop and
restart the server.

5.3 KNOWN PROBLEMS
------------------
RUNNING DOS UTILITIES ON A NETWORK DRIVE
Four DOS utilities, SDDLP, DDLPROC, DDLGEN and RDSADM, will not function
correctly if a file being copied from the server to the current directory
already exists.  For example, SDDLP copies a file named SDDLP.OUT from the
server.  When the utility attempts to copy over the existing file, it fails
with a message of the form:
     open|write error for file '...'
The existing file is not modified.  To avoid this problem, run the
utilities from a local hard drive, or delete any old output files before
running them.

CREATING DEVICES WITH ADMIN
If you create a new database device (or modify an existing database device)
with ADMIN and associate it with a physical path that does not exist on the
server, you must manually create the path.  The system will not create a
path for you.  ADMIN will reject an attempt to use a directory which
doesn't exist.

AN SQL DDL FILE CANNOT USE THE SUFFIX ".DDL"
SDDLP, the SQL ddl processor, creates an intermediate DDL file for
submission to DDLP, the Raima Data Manager DDL processor, and uses the .ddl
suffix for this file.

THE DAL UTILITY DOES NOT RECOGNIZE GROUP LOCK REQUESTS
The RDS User's Guide discusses a syntax for entering group lock requests in
DAL.  This type of request is not available though DAL at the present time.

SOME FUNCTIONS ARE NOT YET AVAILABLE THROUGH DAL
The following functions have not yet been implemented in dal: d_keydir,
d_pkeyfind, d_pkeynext, d_pkeyprev, d_keyrdstate, d_keyszstate,
d_keywrstate, and d_tractive.

=====================================================================
6. SQL INFORMATION
=====================================================================
6.1 PLEASE NOTE
---------------
RERUNNING SDDLP
When you rerun SDDLP on an existing database, a new version of the database
is created.  This new version has new id numbers assigned to the tables.
Any views or stored procedures that existed on the prior version are
invalidated by the new version.  You will need to recreate those view and
stored procedure definitions.  Thus, it is best to save them in RSQL script
files so they can be easily resubmitted after rerunning SDDLP.  (An RSQL
script file is a text file containing RSQL commands and SQL statements that
is invoked using the .r RSQL command -- see Section 2.4 of the SQL Language
Guide.)  You should also save your GRANT statements in RSQL script files.

Also note that when you rerun SDDLP on a database that is referenced in
other databases, you must rerun SDDLP on the dependent databases as well.

In order to remove the old versions of an SQL database definition from
syscat, you need to start with a "clean" syscat and rerun SDDLP on all of
your SQL schema files using the "-o" option (see NEW SDDLP OPTIONS in
Section 5.2 below).  A "clean" syscat is produced by reinstalling the SQL
syscat from the RDS installation, or by replacing the SYSCAT.0* files in
the catalog directory with a copy of those files that you may have saved in
a separate directory after installing RDS.  After rerunning SDDLP on the
SQL schemas, you will need to reprocess (probably through RSQL unless you
have your own program) your GRANT, CREATE VIEW, and CREATE PROCEDURE
statements that had been defined for those databases.

RDS USER NAMES
In the SQL GRANT statement, user names are specified as identifiers.
Identifiers are automatically converted to upper-case.  RDS allows for
mixed-case user names.  Thus, if the ANSI standard form of GRANT is to be
used you must install your user names into RDS as all upper-case
identifiers.   RDS SQL provides a form of the GRANT statement that allows
user names to be specified as a string.  This form, however, is non-
standard.

BUILT-IN SQL ADMINISTRATOR USER
RDS SQL has a built-in administrator user with a secret password.  This
user name is used by the SDDLP utility to connect to SQL during processing
of an SQL DDL specification.  If the password for "sqladmin" is ever
changed, SDDLP will no longer work.  (You could use this as a quick and
dirty technique to prevent use of SDDLP.)

CHANGING MAXIMUM DECIMAL SCALE AND PRECISION
The system default maximum precision for decimal values is 32 digits.  The
system default maximum scale for decimal values is 16 digits.
Administrator users can issue the following UPDATE statements to adjust
these default maximum values as follows:

     update sysparms set maxprecision = dd;
     update sysparms set maxscale = dd;

NOTE: These (and any other changes to sysparms parameters - see Section
12.5 in the SQL Language Guide) DO NOT TAKE EFFECT UNTIL RDS SQL IS
RESTARTED ON THE SERVER.  This restart occurs after the last user
disconnects and the next user connects.

READ REPEATABILITY
Please note that when read repeatability is turned on, RDS SQL will keep
read locks on all CANDIDATE rows, not just RESULT rows.  That means all
rows that are accessed by the SELECT statement are locked, not just the
rows returned by the SELECT.   Thus, this mode is best used when the SELECT
statements within a transaction include simple relational expressions on
indexed columns in the WHERE clause, so that the execution plan will access
only the needed rows.

RELOADING SALES AND INVENTORY FROM LOAD.SLD SCRIPT
The example sales and inventory databases that are included in this
delivery have a user-defined function trigger defined on the item table
that checks and updates the inventory database as well as creating new rows
in the ship_log table.  These databases are delivered with all of the data
preloaded.  If you reinitialize these databases and wish to reload the
data, an RSQL utility script is provided called LOAD.SLD that will do this
for you.  Please note, however, that the item table load will take several
minutes to load because of the extra work being performed in the trigger
function.


6.2 NEW FEATURES NOT DESCRIBED IN MANUALS
-----------------------------------------
6.2.1 NEW SDDLP OPTIONS
-----------------------
Several new command line options have been added to SDDLP to assist users
in schema version control in the SQL syscat and for use by applications
that also use the low-level RDS ("d_") API.

-o               SDDLP by default does not allow a database to be defined
                 that does not exist in the SQL syscat but has already
                 been registered with RDS.  The assumption is that a non-
                 SQL RDS database of the same name already exists.
                 However, in order to delete old versions of a schema a
                 "clean" syscat must be used, this condition could
                 legitimately occur (see RERUNNING SDDLP in section 5.1
                 above).  This option will allow the database definition
                 to be accepted even when the database has been
                 preregistered under RDS.

-u               SDDLP version 1.0 would automatically create a new
                 version of a database when a CREATE DATABASE was issued
                 on an existing database definition.  If the new schema
                 was not a new version of the existing database but a
                 different database, SDDLP would invalidate the old one.
                 In version 1.2.0, SDDLP will fail if there is an existing
                 database of the same name.  The -u option can be used to
                 indicate that the new schema is an update of an existing
                 one.

-f               This option will cause SDDLP to return to the client the
                 RDS DDL file (dbname.ddl) and the header file that was
                 created by the RDS DDLPROC utility (either dbname.h or
                 dbname.hpp).  This option is for applications that use
                 the low-level RDS API or Raima Object Manager.

-d "ddlp opts"   This option can be used to pass the RDS DDLPROC command
                 line options specified in "ddlp opts" through to DDLPROC
                 when it is invoked by SDDLP.  For example,
                 
                 sddlp -f -d "-oo" dbname
                 
                 will pass the "-oo" option to DDLPROC and return
                 dbname.ddl and dbname.hpp back to the client workstation.

6.2.2 OPTIONAL INDEXES
----------------------
A new attribute has been added to the CREATE INDEX DDL statement to specify
that an index is optional.  The key values contained in optional indexes
are only stored and the index can only be used when the optional index is
active.  Two new DML statements are used to ACTIVATE and DEACTIVATE an
optional index.

The syntax for CREATE INDEX is identical to that described on page 13-32 of
the SQL Language Guide except as shown below.

     CREATE [OPTIONAL | UNIQUE] INDEX ...

An optional index cannot be unique.  Optional indexes are initially
inactive.

The syntax for the new DML statements are shown below.

     {ACTIVATE | DEACTIVATE} [OPTIONAL] INDEX indexname;

The ACTIVATE statement will lock the table on which indexname has been
defined and then perform a table scan, storing in the index all key values
that are not presently in the index.  The index will then be marked as
active so that any subsequent INSERT statements will cause the index keys
to be stored.  If the index is already active, the statement simply returns
with SQL_SUCCESS.

The DEACTIVATE statement will mark the index as inactive so that any
subsequent INSERT statements will NOT store the index key values.

The SQL query optimizer will only utilize active indexes.  If a view or
stored procedure is executed that uses an inactive index, SQL will return
an error code (errACTINDEX, 14039) indicating the condition.

The implementation of optional indexes in SQL utilizes the optional key
feature in the RDS DDL.  If you are using this capability with a low-level
RDS (i.e., "d_") API, it is important to note that the activation of an
index occurs strictly at the SQL level.  Thus, while an INSERT statement
will automatically store the key values for an active optional index, the
d_fillnew function will not.

SECURITY LOGGING
All GRANT and REVOKE statements that have been executed are now logged in
the SQL syscat.  The statements are tracked based on the user who issued
the statement and the object to which the GRANT or REVOKE pertains.

The following query will display security statements that have been issued
by all users.

     select user_name, issued, txtln from sysseclog, systext
          where sysseclog.log_addr = systext.log_addr;

To find all of the security commands issued on database "SALES", use the
query below.

     select syslookup.name, user_name, txtln
          from syslookup, sysseclog, systext
          where syslookup.lookup_addr = sysseclog.obj_addr
          and sysseclog.log_addr = systext.log_addr
          and syslookup.qual_name = "SALES"

6.2.3 RETRIEVING VIEW AND STORED PROCEDURE DEFINITION TEXT
----------------------------------------------------------
View and stored procedure definition strings can be retrieved from the
system catalog.  Each line of text in the definition is stored as a row in
a table called systext and is related to either sysview (through a foreign
key called view_addr) or sysproc (through a foreign key called procid).
For example, the following query will show the definitions of all views.

     select name, txtln from sysview, systext
          where sysview.view_addr = systext.view_addr;

The query below will show the definition of a stored procedure called
"SQLTABLES".

     select txtln from sysproc, systext
          where sysproc.name = "SQLTABLES"
          and sysproc.procid = systext.proc_id;

Issue the following SELECT statement to find the view definitions that have
been created by user "admin".

     select sysview.name, txtln from sysuser, sysview, systext
          where sysuser.name = "admin"
          and sysuser.name = sysview.owner_name
          and sysview.view_addr = systext.view_addr;

6.2.4 DEFINING C DATA COLUMNS IN RDS SQL
----------------------------------------
Special columns can be declared in RDS SQL DDL to contain C data values.
These C data values map directly into RDS DDL constructs.  This feature is
provided so that RDS applications that use the d_ API for data entry and
modifications can utilize SQL for queries and reports.

In this release, tables containing columns of type c_data cannot be
modified through SQL.  Thus, the only SQL statement that is allowed on a
table that contains c_data columns is SELECT - INSERT, UPDATE, and DELETE
will be rejected.   Modifications to these tables must be made using the d_
RDS API.

The syntax for declaration of c_data columns is given below (the complete
column declaration syntax is provided on page 13-37 of the SQL Language
Guide).   Upper-case identifiers correspond to reserved words.

----------------------------------------------------------------------
type_spec
     :    C_DATA array_dims c_type_spec

c_type_spec
     :    base_type
     |    STRUCT '{'
               base_type field_name array_dims;
               [base_type field_name array_dims;]...
          '}'
     
array_dims
     :    ['['dim1']'[, '['dim2']'][, '['dim3']']]
     
base_type
     :    [UNSIGNED] {CHAR | SHORT |  INT |  LONG} |  FLOAT | DOUBLE
----------------------------------------------------------------------

The quoted brackets ('[', ']') and braces ('{', '}') are characters that
must be specified in the actual declaration.  The unquoted brackets ([, ])
and braces ({, }) are the meta-symbols of the grammar notation where the
brackets indicate optional items and the braces mean that one of the listed
alternatives must be specified.

The c_data column can be an array of up to three dimensions.  If the column
is a struct each struct field can be an array of up to three dimensions.

Columns of type c_data cannot be
     -    used as a column in an index
     -    referenced in a CHECK constraint
     -    included in a PRIMARY, UNIQUE or FOREIGN KEY clause
     -    specified as a sort column of a CREATE JOIN
     
An example SQL DDL containing a variety of c_data columns is shown below.

--------------------------------------------------------------------
create database cdata
     disable null values
     disable references count;

create table cd1
(
    cd1_name char(32),
    cd1_t01  c_data[2][3] float,
    cd1_t02  c_data struct {
        char  v1;
        short x1[3];
        short y1[3];
        long  z1;
    },
    cd1_t03  c_data[2] struct {
        float  x2[3];
        double y2[3];
        long   z2;
        char   descr[3][30];
    },
    cd1_t04  smallint,
    primary key(cd1_name, cd1_t04)
);
create unique index cd1_key on cd1(cd1_name, cd1_t04);
create table cd2
(
    cd2_name char(32),
    cd2_t01  c_data[2][3][2] float,
    cd2_t02  c_data[2][3] unsigned int
);
create table cd3
(
    cd3_name char(32),
    cd3_t01  c_data[2][3][10] char,
    cd3_t02  c_data struct {
        unsigned int iv;
        char cv[10];
    }
);
--------------------------------------------------------------------

As you can see from the correspoding RDS DDL specification that is
generated by SDDLP and shown below, the declaration maps directly.

--------------------------------------------------------------------
database cdata {
   data file file_cd1 = "cdata.000" contains cd1;
   key  file file_cd1_key = "cdata.001" contains cd1_key;
   data file file_cd2 = "cdata.002" contains cd2;
   data file file_cd3 = "cdata.003" contains cd3;
   record cd1 {
      char    cd1_name[33];
      float   cd1_t01[2][3];
      struct {
         char    v1;
         short   x1[3];
         short   y1[3];
         long    z1;
      } cd1_t02;
      struct {
         float   x2[3];
         double  y2[3];
         long    z2;
         char    descr[3][30];
      } cd1_t03[2];
      short   cd1_t04;
      compound unique key cd1_key {
         cd1_name asc;
         cd1_t04 asc;
      }
   }
   record cd2 {
      char    cd2_name[33];
      float   cd2_t01[2][3][2];
      unsigned int cd2_t02[2][3];
   }
   record cd3 {
      char    cd3_name[33];
      char    cd3_t01[2][3][10];
      struct {
         unsigned int iv;
         char    cv[10];
      } cd3_t02;
   }
}
--------------------------------------------------------------------

ACCESSING C_DATA COLUMN VALUES
RDS SQL provides three ways in which c_data column values can be accessed.

     1.   Directly bind the column value to a program variable by
          specifying SQL_C_DATA as the type parameter to SQLBindCol.
          
     2.   Retrieve a textual representation of the data by specifying
          SQL_C_CHAR as the type paramater to SQLBindCol.
          
     3.   Call the built-in function c_data() from your select statement.
          
Each of these methods is illustrated in the following examples.
     
By the way, function SQLDescribeCol will return a new RDS-specific data
type indicator, SQL_CDATA, for columns of type c_data.

BINDING DIRECTLY WITH SQL_C_DATA
The following example illustrates how to call SQLBindCol in order to
retrieve a complete c_data result value.  This program includes the header
file generated by the RDS DDLPROC (cdata.h).  This file can be fetched by
calling SDDLP with the -f command line option.  It contains structure
declarations associated with each of the RDS DDL record types.  These can
then be used to declare the local program variables into which the c_data
column values can be bound.

Note that the buflen argument to SQLBindCol must be specified as the actual
size of the entire array or struct variable.

----------------------------------------------------------------------
...

/* must include sqlrds.h to use c_data features */
#include "sqlrds.h"

/* cdata.h is the cdata database header generated by ddlproc */
#include "cdata.h"

... other declarations

/* select statements for retrieving data from database "cdata" */
static char stmt1[] =
     "select cd1_name, cd1_t01, cd1_t02, cd1_t03 from cd1";

... startup code

/* compile and process stmt1 */
SQLPrepare(hstmt, stmt1, SQL_NTS);
SQLBindCol(hstmt, 1, SQL_C_CHAR,  c1r.cd1_name, 33, NULL);
SQLBindCol(hstmt, 2, SQL_C_DATA,  &c1r.cd1_t01, sizeof(c1r.cd1_t01), NULL);
SQLBindCol(hstmt, 3, SQL_C_DATA,  &c1r.cd1_t02, sizeof(c1r.cd1_t02), NULL);
SQLBindCol(hstmt, 4, SQL_C_DATA,  &c1r.cd1_t03, sizeof(c1r.cd1_t03), NULL);
SQLExecute(hstmt);
while ( (stat = SQLFetch(hstmt)) == SQL_SUCCESS ) {
    printf("-----------------------------------------\n");
    printf("cd1_name: %s\n", c1r.cd1_name);
    printf("cd1_t01 : {{%.2f,%.2f,%.2f},{%.2f,%.2f,%.2f}}\n",
        c1r.cd1_t01[0][0],c1r.cd1_t01[0][1],c1r.cd1_t01[0][2],
        c1r.cd1_t01[1][0],c1r.cd1_t01[1][1],c1r.cd1_t01[1][2] );
    printf("cd1_t02 : {'%c', {%d,%d,%d},{%d,%d,%d},%ld}\n",
        c1r.cd1_t02.v1,
        c1r.cd1_t02.x1[0],c1r.cd1_t02.x1[1],c1r.cd1_t02.x1[2],
        c1r.cd1_t02.y1[0],c1r.cd1_t02.y1[1],c1r.cd1_t02.y1[2],
        c1r.cd1_t02.z1);
    printf("cd1_t03 : "
       "{%.2f,%.2f,%.2f},{%.2lf,%.2lf,%.2lf},%ld,{%s,%s,%s}}\n",
        c1r.cd1_t03[0].x2[0],c1r.cd1_t03[0].x2[1],c1r.cd1_t03[0].x2[2],
        c1r.cd1_t03[0].y2[0],c1r.cd1_t03[0].y2[1],c1r.cd1_t03[0].y2[2],
        c1r.cd1_t03[0].z2,
        c1r.cd1_t03[0].descr[0],
        c1r.cd1_t03[0].descr[1],
        c1r.cd1_t03[0].descr[2]);
    printf("          "
        "{{%.2f,%.2f,%.2f},{%.2lf,%.2lf,%.2lf},%ld,{%s,%s,%s}}\n",
        c1r.cd1_t03[1].x2[0],c1r.cd1_t03[1].x2[1],c1r.cd1_t03[1].x2[2],
        c1r.cd1_t03[1].y2[0],c1r.cd1_t03[1].y2[1],c1r.cd1_t03[1].y2[2],
        c1r.cd1_t03[1].z2,
        c1r.cd1_t03[1].descr[0],
        c1r.cd1_t03[1].descr[1],
        c1r.cd1_t03[1].descr[2]);
}
SQLFreeStmt(hstmt, SQL_CLOSE);

...
----------------------------------------------------------------------

BINDING C_DATA COLUMNS TO SQL_C_CHAR
A textual representation of c_data column values will be returned when a
column with an SQL data type of SQL_CDATA is bound to a character array
through the C type specified SQL_C_CHAR as shown in the following example.

----------------------------------------------------------------------
char *txtbuf;
UDWORD maxDisplayWidth;
...
SQLPrepare(hstmt, "select cd1_t02 from cd1", SQL_NTS);
SQLDescribeCol(hstmt,1,colname,33,NULL,NULL,&maxDisplayWidth,NULL,NULL);
txtbuf = malloc(maxDisplayWidth+1);
SQLBindCol(hstmt,2,SQL_C_CHAR,txtbuf,(SDWORD)maxDisplayWidth,NULL);
SQLExecute(hstmt);
while ( SQLFetch(hstmt) == SQL_SUCCESS ) {
   printf("%s\n", txtbuf);
}
...
----------------------------------------------------------------------

The resulting string is in the standard C static variable initializer
format as shown below.

----------------------------------------------------------------------
select cd3_t02 from cd3;
CD3_T02
{1,"Randy"}
{2,"Wayne"}
{3,"Brad "}
{4,"Rich "}
{5,"Brian"}
{6,"Lyle "}
{7,"Bob  "}
{8,"Tim  "}

select cd1_t02 from cd1;
CD1_T02
{'a',{1,0,1},{1,0,2},100100}
{'b',{2,0,1},{2,0,2},100200}
{'c',{3,0,1},{3,0,2},100300}
{'d',{4,0,1},{4,0,2},100400}
{'e',{5,0,1},{5,0,2},100500}
{'f',{6,0,1},{6,0,2},100600}
{'g',{7,0,1},{7,0,2},100700}
{'h',{8,0,1},{8,0,2},100800}
----------------------------------------------------------------------


USING THE C_DATA BUILT-IN FUNCTION
Individual elements of a c_data column can be retrieved using the c_data
built-in function.    The c_data function call syntax is given below.

----------------------------------------------------------------------
C_DATA(colname['['sub1']'[, '['sub2']'][, '['sub3']']]
       [,eltname['['sub1']'[, '['sub2']'][, '['sub3']']]])
----------------------------------------------------------------------
The colname is the name of the column.  This name can be qualified by the
table or correlation name (e.g., cd1.cd1_t03).   If the c_data column is an
array, the colname must have the appropriate number of specified
subscripts.  The subscripts are specified in the usual C notation.  If the
column is a struct, then the second argument to the c_data function must be
specified.  This argument must be the name of the struct field to be
accessed.  If the struct field is an array then it must have the correct
number of specified subscripts.  The subscript specifiers can be any
expression that returns a smallint value.  Parameter markers are allowed in
place of the expression.

The following example returns the v1 field of the cd1_t02 struct.

----------------------------------------------------------------------
select c_data(cd1_t02,v1) from cd1;
C_DATA(CD1_T02,V1)
a
b
c
d
e
f
g
h
----------------------------------------------------------------------

The next example returns element 0 of the x1 array of the cd1_t02 struct
column.

----------------------------------------------------------------------
select c_data(cd1_t02,x1[0]) from cd1;
C_DATA(CD1_T02,X1[?])
                    1
                    2
                    3
                    4
                    5
                    6
                    7
                    8
----------------------------------------------------------------------

The next example uses a parameter marker for the x1 subscript.  Parameter
values can be specified in the RSQL utility using the .p command.  The
statement is then executed with the .x command.   RDS SQL will ensure that
the subscript values are in the declared range.

----------------------------------------------------------------------
select c_data(cd1_t02,x1[?]) from cd1;
.p 1
.x
C_DATA(CD1_T02,X1[?])
                    0
                    0
                    0
                    0
                    0
                    0
                    0
                    0
.p 2
.x
C_DATA(CD1_T02,X1[?])
                    1
                    1
                    1
                    1
                    1
                    1
                    1
                    1
.p 3
.x
****RSQL Error 3737: subscript out of range: X1
----------------------------------------------------------------------

The next statement selects elements from both the arrayed field, y2, and
the arrayed struct cd1_t03.

----------------------------------------------------------------------
select c_data(cd1_t03[?], y2[?]) from cd1;
     .p 0 0
     .x
     C_DATA(CD1_T03[?], Y2[?])
                      1.010000
                      1.110000
                      1.210000
                      1.310000
                      1.410000
                      1.510000
                      1.610000
                      1.710000
     .p 1 2
     .x
C_DATA(CD1_T03[?], Y2[?])
                 2.030000
                 2.030000
                 2.030000
                 2.030000
                 2.030000
                 2.030000
                 2.030000
                 2.030000
----------------------------------------------------------------------

All arrays, except those of type char, must be fully subscripted.
Character arrays can either be fully subscripted, in which case the single
character is returned, or the last dimension may be omitted, in which case
the result is interpreted as a multi-dimension character string and a
string is returned.

The descr field of column cd1_t03 is a two-dimensional character array that
is actually an array of 30 byte null-terminated character strings.   In the
example below, descr is specified with just one subscript so that c_data
returns a string.

----------------------------------------------------------------------
select c_data(cd1_t03[0], descr[?]) from cd1;
.p 0
.x
C_DATA(CD1_T03[0], DESCR[?])
RLM01
WLW01
BJB01
RCH01
BNS01
LK001
BCQ01
TT001
.p 2
.x
C_DATA(CD1_T03[0], DESCR[?])
RLM03
WLW03
BJB03
RCH03
BNS03
LK003
BCQ03
TT003
----------------------------------------------------------------------

In the next example, descr is specified with both subscripts so that c_data
returns a single character.

----------------------------------------------------------------------
select c_data(cd1_t03[1], descr[?][?]) from cd1;
     .p 0 0
     .x
     C_DATA(CD1_T03[1], DESCR[?][?])
     R
W
B
R
B
L
B
T
.p 0 1
.x
C_DATA(CD1_T03[1], DESCR[?][?])
L
L
J
C
N
K
C
T
----------------------------------------------------------------------

6.2.5 ACCESSING SQL-SPECIFIC DATA TYPES: DATE, TIME, TIMESTAMP, DECIMAL
-----------------------------------------------------------------------
Included in this release is a library of functions that allow an RDS d_
application to access and manipulate SQL-specific data values.

Use of these functions requires that the "sqlrds.h" file be included in the
program.

Error codes that can be returned by these functions are defined in the
"valerrs.h" header file.

WARNING: There is no SQL constraint checking on records changed via the RDS
d_ API.  Therefore, if you have columns on which you have defined
constraints you will need to validate the values in your application before
writing to the database.

6.2.5.1 DATE/TIME VALUE MANIPULATION FUNCTIONS
----------------------------------------------------------------------
Function            Description
--------            -----------
VALUnpackDate       Unpacks an RDS SQL date from its internal format into
                    its constituent parts as defined in the DATE_STRUCT
                    structure.

VALUnpackTime       Unpacks an RDS SQL time from its internal format into
                    its constituent parts as defined in the TIME_STRUCT
                    structure.

VALUnpackTimestamp  Unpacks an RDS SQL timestamp from its internal format
                    into its constituent parts as defined in the
                    TIMESTAMP_STRUCT structure.

VALPackDate         Packs a DATE_STRUCT date into the RDS SQL internal
                    storage format.

VALPackTime         Packs a TIME_STRUCT date into the RDS SQL internal
                    storage format.

VALPackTimestamp    Packs a TIMESTAMP_STRUCT date into the RDS SQL internal
                    storage format.
----------------------------------------------------------------------

These functions are described in detail below.  Note that the *_VAL data
types are always associated with the internal storage format and the
*_STRUCT data types are the standard ODBC types.  The typedef's for the
_VAL data types are shown below.  Note that these struct definitions are
NOT currently emitted by DDLPROC -- they are declared using the base C
types.

typedef long DATE_VAL;
typedef long TIME_VAL;

typedef struct {
    DATE_VAL date;
    TIME_VAL time;
} TIMESTAMP_VAL;

----------------------------------------------------------------------
RETCODE REXTERNAL VALUnpackDate(
    DATE_VAL      RFAR *dvp,
    DATE_STRUCT   RFAR *dsp
);

DESCRIPTION
-----------
VALUnpackDate converts an RDS SQL date from its internal format into the
standard ODBC format.

EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

DATE_VAL ord_date;
DATE_STRUCT order_date;
     ...
d_crread(SALES_ORDER_ORD_DATE, &ord_date, hDb);
VALUnpackDate(&ord_date, &order_date);
printf("order date: %02d-%02d-%04d\n",
     order_date.month, order_date.day, order_date.year);

----------------------------------------------------------------------
RETCODE REXTERNAL VALUnpackTime(
    TIME_VAL      RFAR *tvp,
    TIME_STRUCT   RFAR *tsp
);

DESCRIPTION
-----------
VALUnpackTime converts an RDS SQL time from its internal format into the
standard ODBC format.

EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

TIME_VAL ord_time;
TIME_STRUCT order_time;
     ...
d_crread(SALES_ORDER_ORD_TIME, &ord_time, hDb);
VALUnpackTime(&ord_time, &order_time);
printf("order time: %02d:%02d:%02d\n",
     order_time.hour, order_time.minute, order_time.second);

----------------------------------------------------------------------
RETCODE REXTERNAL VALUnpackTimestamp(
    TIMESTAMP_VAL    RFAR *tsvp,
    TIMESTAMP_STRUCT RFAR *tssp
);

DESCRIPTION
-----------
VALUnpackTimestamp converts an RDS SQL timestamp from its internal format
into the standard ODBC format.

EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

TIMESTAMP_VAL ship_date;
TIMESTAMP_STRUCT shipped;
     ...
d_crread(SALES_ORDER_SHIP_DATE, &ship_date, hDb);
if ( ship_date.date ) {
     VALUnpackTimestamp(&ship_date, &shipped);
     printf("ship date/time: %02d-%02d-%04d %02d:%02d:%02d\n",
          shipped.month, shipped.day,    shipped.year,
          shipped.hour,  shipped.minute, shipped.second);
}
----------------------------------------------------------------------
RETCODE REXTERNAL VALPackDate(
    DATE_STRUCT   RFAR *dsp,
    DATE_VAL      RFAR *dvp
);

DESCRIPTION
-----------
VALPackDate converts an ODBC date value into an RDS SQL internal date.

EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

DATE_VAL ord_date;
DATE_STRUCT order_date;
     ...
VALPackDate(&order_date, &ord_date);
d_crwrite(SALES_ORDER_ORD_DATE, &ord_date, hDb);
----------------------------------------------------------------------
RETCODE REXTERNAL VALPackTime(
    TIME_STRUCT   RFAR *tsp,
    TIME_VAL      RFAR *tvp
);

DESCRIPTION
-----------
VALPackTime converts an ODBC time value into an RDS SQL internal time.

EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

TIME_VAL ord_time;
TIME_STRUCT order_time;
     ...
VALPackTime(&order_time, &ord_time);
d_crwrite(SALES_ORDER_ORD_TIME, &ord_time, hDb);

----------------------------------------------------------------------
RETCODE REXTERNAL VALPackTimestamp(
    TIMESTAMP_STRUCT RFAR *tssp,
    TIMESTAMP_VAL    RFAR *tsvp
);

DESCRIPTION
-----------
VALPackTimestamp converts an ODBC time value into an RDS SQL internal
timestamp.

EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

TIMESTAMP_VAL ship_date;
TIMESTAMP_STRUCT shipped;
     ...
VALPackTimestamp(&shipped, &ship_date);
d_crwrite(SALES_ORDER_SHIP_DATE, &ship_date, hDb);

----------------------------------------------------------------------


6.2.5.2 DECIMAL VALUE MANIPULATION FUNCTIONS
----------------------------------------------------------------------
Function            Description
--------            -----------
BCDAllocEnv         Allocate a BCD (Binary-Coded Decimal) environment
                    handle.

BCDFreeEnv          Free a BCD (Binary-Coded Decimal) environment handle.

BCDUnpack           Unpack a BCD value from its RDS SQL internal storage
                    format into a character string.

BCDPack             Convert a character string representation of a decimal
                    value into an RDS SQL internal BCD storage format.

BCDAdd              Add two decimal strings.

BCDSubtract         Subtract two decimal strings.

BCDMultiply         Multiply two decimal strings.

BCDDivide           Divide two decimal strings.

BCDCompare          Compare two decimal strings.

BCDStatus           Return the status of a BCD value.
----------------------------------------------------------------------

Detailed descriptions of each of these functions are provided below.  Note
that the external representation for a decimal value is simply a character
string.  Thus, in effect, this library implements numeric string
arithmetic.

----------------------------------------------------------------------
RETCODE REXTERNAL BCDAllocEnv(
    unsigned char       max_precision,
    unsigned char       max_scale,
    BCD_HENV            RFAR *hBCDp
);

DESCRIPTION
-----------
All BCD functions require the use of a BCD handle.  BCDAllocEnv must first
be called to allocate the BCD environment handle hBCDp.  The maximum
allowed precision and scale for the BCD values to be manipulated through
this BCD handle must be specified.  The BCD environment include dynamically
allocated buffers needed by the BCD operations.

EXAMPLE
-------
#include "sqlrds.h"

BCD_HENV hBcd;
RETCODE stat;
     ...
stat = BCDAllocEnv(32, 16, &hBcd);
if ( stat != VAL_OKAY )
     printf("unable to allocate BCD handle, status = %d\n", stat);

----------------------------------------------------------------------
RETCODE REXTERNAL BCDFreeEnv(
    BCD_HENV            hBCD
);

DESCRIPTION
-----------
All BCD functions require the use of a BCD handle.  BCDFreeEnv is called
after all desired BCD operations have been performed to free all
dynamically allocated memory.

EXAMPLE
-------
#include "sqlrds.h"

BCD_HENV hBcd;
RETCODE stat;
     ...
stat = BCDAllocEnv(32, 16, &hBcd);
if ( stat != VAL_OKAY ) {
     printf("unable to allocate BCD handle, status = %d\n", stat);
     ... cleanup and return
}

...  perform BCD operations

BCDFreeEnv(hBcd);

----------------------------------------------------------------------
RETCODE REXTERNAL BCDUnpack(
    BCD_HENV            hBCD,
    BCD_VAL       RFAR *bv,
    char          RFAR *cp,
    size_t              len
);

DESCRIPTION
-----------
BCDUnpack converts a decimal value (pointed to by bv) from its RDS SQL
internal BCD format into a character string.  Parameter cp is a char array
of len bytes that must be large enough to contain the result value (len
would typically be equal to max_precision+1).

EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

BCD_HENV hBcd;
RETCODE stat;
struct salesperson sp;
char commission[33];

stat = BCDAllocEnv(32, 16, &hBcd);
if ( stat != VAL_OKAY ) {
     printf("unable to allocate BCD handle, status = %d\n", stat);
     ... cleanup and return
}

while ( d_recnext(SALESPERSON, hDb) == S_OKAY ) {
     d_recread(SALESPERSON, &sp, hDb);
     BCDUnpack(hBcd, sp.commission, commission, 33);
     printf("sale_id: %s, sale_name: %s, commission: %s\n",
          sp.sale_id, sp.sale_name, commission);
}

BCDFreeEnv(hBcd);

----------------------------------------------------------------------
RETCODE REXTERNAL BCDPack(
    BCD_HENV            hBCD,
    char          RFAR *cp,
    unsigned char       precision,
    unsigned char       scale,
    BCD_VAL       RFAR *rv,
    size_t              len
);

DESCRIPTION
-----------
BCDPack converts a numeric character string into a decimal in its RDS SQL
internal BCD format with the specified precision and scale.  The result is
stored in the BCD_VAL pointed to by rv that has a length of len bytes (the
length is the sizeof the data field in the RDS record).

IT IS EXTREMELY IMPORTANT when converting into a value that is to be stored
in the database that the precision and scale match the declared precision
and scale for that particular column.  You can call the SQL function
SQLColumns to find out what the declared precision and scale is for any
particular column in the database.

EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

BCD_HENV hBcd;
RETCODE stat;
struct salesperson sp;

stat = BCDAllocEnv(32, 16, &hBcd);
if ( stat != VAL_OKAY ) {
     printf("unable to allocate BCD handle, status = %d\n", stat);
     ... cleanup and return
}

/* fix all commission rates at 8% */
while ( d_recnext(SALESPERSON, hDb) == S_OKAY ) {
     BCDPack(hBcd, "0.08", 4, 3, &sp.commission, sizeof(sp.commission));
     d_crwrite(SALESPERSON_COMMISSION, &sp.commission, hDb);
}

BCDFreeEnv(hBcd);

----------------------------------------------------------------------
RETCODE REXTERNAL BCDAdd(
    BCD_HENV            hBCD,
    char          RFAR *lv,
    char          RFAR *rv,
    char          RFAR *result,
    size_t              rlen
);

DESCRIPTION
-----------
This function performs a BCD addition of two numeric strings, storing the
resulting numeric string in result, a char array of size rlen.

EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

BCD_HENV hBcd;
struct salesperson sp;
char oldcomm[5], newcomm[5];

...

/* increase all commission rates by 1% */
while ( d_recnext(SALESPERSON, hDb) == S_OKAY ) {
     d_crread(SALESPERSON_COMMISSION, &sp.commission, hDb);
     BCDUnpack(hBcd, sp.commission, oldcomm, 5);
     BCDAdd(hBcd, oldcomm, "0.01", newcomm, 5);
     ... validate newcomm (see BCDCompare() example)
     BCDPack(hBcd, newcomm, 4, 3, &sp.commission, sizeof(sp.commission));
     d_crwrite(SALESPERSON_COMMISSION, &sp.commission, hDb);
}

----------------------------------------------------------------------
RETCODE REXTERNAL BCDSubtract(
    BCD_HENV            hBCD,
    char          RFAR *lv,
    char          RFAR *rv,
    char          RFAR *result,
    size_t              rlen
);

DESCRIPTION
-----------
This function performs a BCD subtraction of the numeric string rv from the
numeric string lv, storing the resulting numeric string in result, a char
array of size rlen.


EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

BCD_HENV hBcd;
struct salesperson sp;
char oldcomm[5], newcomm[5];

...

/* decrease all commission rates by 1% */
while ( d_recnext(SALESPERSON, hDb) == S_OKAY ) {
     d_crread(SALESPERSON_COMMISSION, &sp.commission, hDb);
     BCDUnpack(hBcd, sp.commission, oldcomm, 5);
     BCDSubtract(hBcd, oldcomm, "0.01", newcomm, 5);
     ... validate newcomm (see BCDCompare() example)
     BCDPack(hBcd, newcomm, 4, 3, &sp.commission, sizeof(sp.commission));
     d_crwrite(SALESPERSON_COMMISSION, &sp.commission, hDb);
}

----------------------------------------------------------------------
RETCODE REXTERNAL BCDMultiply(
    BCD_HENV            hBCD,
    char          RFAR *lv,
    char          RFAR *rv,
    char          RFAR *result,
    size_t              rlen
);

DESCRIPTION
-----------
This function performs a BCD multiply of two numeric strings, storing the
resulting numeric string in result, a char array of size rlen.


EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

BCD_HENV hBcd;
struct salesperson sp;
char oldcomm[5], newcomm[5];

...

/* increase each commission rate by 10% */
while ( d_recnext(SALESPERSON, hDb) == S_OKAY ) {
     d_crread(SALESPERSON_COMMISSION, &sp.commission, hDb);
     BCDUnpack(hBcd, sp.commission, oldcomm, 5);
     BCDMultiply(hBcd, oldcomm, "1.10", newcomm, 5);
     ... validate newcomm (see BCDCompare() example)
     BCDPack(hBcd, newcomm, 4, 3, &sp.commission, sizeof(sp.commission));
     d_crwrite(SALESPERSON_COMMISSION, &sp.commission, hDb);
}

----------------------------------------------------------------------
RETCODE REXTERNAL BCDDivide(
    BCD_HENV            hBCD,
    char          RFAR *lv,
    char          RFAR *rv,
    char          RFAR *result,
    size_t              rlen
);

DESCRIPTION
-----------
This function performs a BCD division of the numeric string lv by the
numeric string rv, storing the resulting numeric string in result, a char
array of size rlen.


EXAMPLE
-------
#include "sqlrds.h"
#include "sales.h"

BCD_HENV hBcd;
struct salesperson sp;
char oldcomm[5], newcomm[5];

...

/* decrease commission rate by 10% */
while ( d_recnext(SALESPERSON, hDb) == S_OKAY ) {
     d_crread(SALESPERSON_COMMISSION, &sp.commission, hDb);
     BCDUnpack(hBcd, sp.commission, oldcomm, 5);
     BCDDivide(hBcd, oldcomm, "1.10", newcomm, 5);
     ... validate newcomm (see BCDCompare() example)
     BCDPack(hBcd, newcomm, 4, 3, &sp.commission, sizeof(sp.commission));
     d_crwrite(SALESPERSON_COMMISSION, &sp.commission, hDb);
}

----------------------------------------------------------------------
RETCODE REXTERNAL BCDCompare(
    BCD_HENV            hBCD,
    char                RFAR *lv,
    char                RFAR *rv,
    short               RFAR *cmp
);

DESCRIPTION
-----------
This function is used to perform a decimal comparison of two numeric
strings.  The result of the comparison is stored in cmp as follows:

     -1   => lv < rv
      0   => lv == rv
     +1   => lv > rv

EXAMPLE
-------
#include "sqlrds.h"

BCD_HENV hBcd;
char comm[33];
short cmp;

     ...  enter new salesperson

/* validate commission rate */
BCDCompare(hBcd, comm, "0.0", &cmp);
if ( cmp >= 0 )
     BCDCompare(hBcd, "0.15", comm, &cmp);

if ( cmp < 0 )
     ... /* return "commission rate out of range" error */

     ...

----------------------------------------------------------------------
RETCODE REXTERNAL BCDStatus(
    BCD_HENV            hBCD,
    BCD_VAL       RFAR *bcd
);


DESCRIPTION
-----------
Function BCDStatus is used to check the status of a decimal value for
overflow and/or loss of precision.  The status is returned as the function
value.

EXAMPLE
-------
#include "sqlrds.h"

BCD_HENV hBcd;
RETCODE stat;
     ...

stat = BCDStatus(hBcd, sp.commission);
switch ( stat ) {
     case VAL_OVERFLOW: printf("decimal overflow");  break;
     case VAL_PRECLOSS: printf("decimal loss of precision"); break;
     case VAL_OVERLOSS: printf("decimal overflow + precision loss"); break;
}

----------------------------------------------------------------------

6.3 ANSI SQL DISCREPANCIES
--------------------------
The following ANSI 1989 SQL features have not been implemented in this
release:

UNION
The UNION operator allows similar SELECT statements to be executed together
with merged result sets.  You can achieve the same results by executing a
stored procedure that contains separate SELECT statements for each part of
the UNION.

GRANT WITH GRANT OPTION
This feature provides an administrator or database owner the ability to
give other users the right to grant access privileges on a database.  In
RDS SQL only administrator users and the database owner can issue GRANT
permissions for a particular database.

UPDATABLE VIEWS OF VIEWS
In addition to the ANSI specified requirements for view updatability, in
RDS SQL a view is only considered updatable when the referenced tables are
base tables.  Thus, RDS SQL does not yet support updatable views of views.
This capability is currently in development and will be available soon.

NUMERIC DATA TYPE
This is a generic data type that leaves the decision as to how the data
will be stored to the SQL system.  Typically, a NUMERIC will map into
either an INTEGER, SMALLINT, or DECIMAL depending on the specified
precision and scale.  If you are converting an SQL schema that uses
NUMERIC, please do not simply convert them to DECIMAL.  DECIMAL arithmetic
is the most accurate representation, but it is also the slowest.  Thus,
NUMERIC types that have precision but not SCALE specified (or a SCALE of 0)
should be converted to SMALLINT (if the precision is 5 or less), INTEGER
(if the precision is between 6 and 10), or DECIMAL (if the precision is
greater than 10).

MODULES and EMBEDDED SQL
The only DML execution method that is defined as part of the 1989 ANSI
standard is through use of the MODULE and PROCEDURE constructs.  Embedded
SQL is defined but is identified as an "annex" and not an integral part of
the standard.  RDS SQL has adopted the SQL Access Group/Microsoft ODBC call-
level interface standard instead.

LIKE ESCAPE CHARACTER
This is an optional clause of the LIKE operator that allows a user to
specify a character that can be used to "escape" one of the meta symbols
(e.g., the "wildcard" characters '%' and '_') so that the actual character
can be included in the search.  RDS SQL has a built-in escape character,
the back-slash ('\').

UPDATABLE VIEWS WITH CHECK OPTION AND NULLS
The ANSI semantics concerning null values differ between CHECK constraints
on tables and the WITH CHECK OPTION in views. With CHECK constraints on
base tables, a null value does not violate the constraint (the logic
appears to be that since there is the NOT NULL clause, it is sufficient to
only require the CHECK to return not false -- comparisons with nulls have
result "unknown").  The WITH CHECK CLAUSE constraint, however, must be true
for each row.  Thus a null comparison does invalidate the constraint.  RDS
SQL treats constraints involving nulls the same way for both tables and
views, following the semantics for the CHECK clause on the base table.   A
future RDS update will correct this problem.

HAVING CLAUSE CONTAINING A SUBQUERY
ANSI allows subqueries to be specified in the HAVING clause.  They are used
for comparing aggregate results from the outer query in the WHERE clause of
the inner query.  RDS SQL does not allow an aggregate function to be
specified in the WHERE clause, thus precluding this capability.  A work-
around for this is to INSERT the results of the outer query into a
temporary table, and then do a SELECT between that temporary table and the
original subquery (this new statement could be either a join or a
subquery).

PADDING STRINGS WITH SPACES
ANSI SQL requires that all strings be padded with spaces.  As RDS SQL has
been designed to work primarily with C application programs, it uses
standard C null-terminated strings.

DATABASE AND TABLE NAME QUALIFIERS ON COLUMN NAMES
ANSI SQL allows both the database name (i.e. AUTHORIZATION id), and the
table name to be prepended to the column name in a column specification.
RDS SQL only allows for a table name qualifier.  The table name can be
qualified by a database name in the FROM clause.  The work-around is to
specify a correlation name on all qualified table names in the FROM clause,
and then to qualify the column names with the correlation name.

DUPLICATE TABLE NAMES BETWEEN DATABASES
RDS SQL automatically opens a database when it encounters the first
reference to a column, table, or view contained in the database.  If an
unqualified table name is referenced and there is more than one database
that contains a table of that same name, RDS SQL will automatically open
the first one it finds.  Unfortunately, this may not be the one you want.
The solution is to explicitly OPEN the databases needed by your
application.  If two databases containing tables with the same name are
opened, RDS SQL will pick the first opened database to resolve an ambiguous
reference.  Again, this may not be the one you want.  In this case, you
need to explicitly qualify the table names with the correct database names.

6.4 KNOWN PROBLEMS
------------------
OPTIMIZATION OF VIEW REFERENCES
All views in RDS SQL are optimized at view creation time and stored in a
compiled format.  When a view is referenced in a SELECT statement, it is
accessed according to its pre-compiled execution plan.  This can cause
performance problems when a view is joined with some other table.  Thus, it
is best to avoid doing joins that involve views.  (Of course, a view
definition can include joins on base tables.)

CREATE JOIN WITH ORDER SORTED
The ORDER SORTED clause of the CREATE JOIN statement allows the referencing
rows to be sorted by the specified columns.  Each column can have a sort
order of ASCENDING or DESCENDING.  Sort orders of mixed ASCENDING and
DESCENDING columns are not supported.  The columns are only stored in
ASCENDING order.

REVOKE
According to the X/Open SQL standard, when a user's SELECT privileges on a
table are revoked, all views that were created by that user on that table
are supposed to be automatically dropped.  RDS SQL does not currently do
this.  You can discover the views that a particular user has created from
the SQL syscat using the following SELECT statement:

     SELECT SYSVIEW.NAME FROM SYSVIEW, SYSUSER
          WHERE SYSUSER.NAME = "username"
               AND SYSUSER.NAME = SYSVIEW.OWNER_NAME;

OPTIMIZATION OF SELECT FROM PATH
When the FROM PATH clause of the SELECT statement is used, the only
optimization that is performed is based on the use of index or rowid
columns from the first table in the path in the WHERE clause.  Only
relational expressions of the form "COL = VALUE" will be optimized.

DECIMAL LITERALS IN DDL
The use of decimal literals in DEFAULT and CHECK clauses of the CREATE
TABLE statement are currently stored as doubles.  Thus, the maximum
precision of those literal constants is limited to 15 digits (more digits
can be specified, but the precision beyond 15 digits will be lost).

DATE ARITHMETIC IN DDL
Date arithmetic (e.g., subtracting one date from another or adding an
integer to a date) is not supported in the DDL.

SQL EXTENSION MODULES REQUIRE SQL TO BE USED BEFOREHAND
The example SQL extension module (useemsql.c and emsql.c) will fail to load
correctly if SQL has not been used prior to the use of EMSQL.  This can be
done through a simple connect in RSQL:
     [C:\] rsql
     001 rsql: .c 1 rds admin secret
     001 rsql: .q
Then the SQL extension module can be used.  This restriction will be
corrected in a future release.

=====================================================================
7. ODBC INFORMATION
=====================================================================
Please refer to section 3.7 of the SQL C Programmer's Guide for more
information on the use of RDS SQL under the Microsoft Windows ODBC driver
manager.

7.1 ODBC ADMIN UTILITY
The ODBC administration utility now provides an additional field entry in
the configuration dialog box that allows you to specify the name of the RDS
server.  By default, the server name is the same as the data source (RDS).
However, a given server name can be used with different data sources.  You
can now add as many data source names and servers as you like.  This
utility is automatically invoked by the ODBC installation setup.

7.2 VISUAL BASIC USAGE
Visual Basic 2.0 header files have been supplied in the Windows Client
installation include directory. These files have a .gbl extension.

For non-Windows platforms an environment variable called ODBC_INI can be
set to the location of the odbc.ini file.  The file name must be included
in the path as in the following example:

     set ODBC_INI=\rds\init\myodbc.ini"

Windows ODBC installations default to having auto commit mode turned on.
This can be changed using an odbc.ini option.  The CommitMode line in the
odbc.ini file is set to "auto" or "manual" (anything other than "auto" is
treated as "manual").

=====================================================================
8. LOW-LEVEL RDS API INFORMATION
=====================================================================
8.1 PLEASE NOTE
---------------
The first parameter to the callback function for d_set_dberr is now a
short.  The type of this callback function is:
     void REXTERNAL

8.2 NEW FEATURES NOT DESCRIBED IN MANUALS
-----------------------------------------
GUARANTEED NON-VALID DATABASE AND SESSION HANDLES
The include file "rdsbasic.h" now provides definitions of constants which
are never used as handles:
     NO_DB     (never a database handle)
     NO_SESS   (never a session handle)

STATUS (NOT AN ERROR) RETURN FROM SOME FUNCTIONS
The value S_NOTFOUND is returned from the functions d_recfrst and d_reclast
if no records are found of the specified record type.

The value S_NOTFOUND is returned from d_keydel (used to delete optional
keys) if the key was not indexed.

8.3 KNOWN PROBLEMS
------------------
None.

=====================================================================
9. BUG FIXES
=====================================================================
Below are described the bugs that have been fixed since release 1.0.1.

SQL            SQL could only accomodate a database containing less that
               about 3000 column definitions.  If a database had too many
               columns SQL would crash in unpredictable ways.

SQL            Outer join predicates referenced in WHERE clauses containing
               other conditional expressions could cause invalid results to
               be returned from the SELECT statement.

SQL            Incorrectly formatted date and time values in an import file
               (i.e., insert into tabname from file ...) were not detected
               causing the server to hang.

SDDLP          SDDLP was not initializing the new files in a database
               upgrade (-u).

SDDLP          SDDLP was not gracefully terminating when it was unable to
               open SYSCAT.

SERVER         Locks obtained outside a transaction were not cleared if the
               client logged out (or disconnected) without clearing them.
=====================================================================
END OF FILE
=====================================================================
