TD Connecting SQLWindows Objects to Databases
TD Connecting SQLWindows Objects to Databases
Team Developer
Connecting SQLWindows Objects to Databases
Legal Notice
Gupta, Gupta Technologies, the Gupta logo, Gupta Powered, the Gupta Powered logo, ACCELL, Centura, Centura
Ranger, the Centura logo, Centura Web Developer, Component Development Kit, Connectivity Administrator,
DataServer, DBIntegrator, Development Kit, eWave, Fast Facts, NXJ, Object Nationalizer, Quest, Quest/Web,
QuickObjects, RDM, Report Builder, RPT Report Writer, RPT/Web, SQL/API, SQLBase, SQLBase Exchange, SQLBase
Resource Manager, SQLConsole, SQLGateway, SQLHost, SQLNetwork, SQLRouter, SQLTalk, Team Developer, Team
Object Manager, TD Mobile, Velocis, VISION, Web Developer and WebNow! are trademarks of Gupta Technologies and
may be registered in the United States of America and/or other countries.
SQLWindows is a registered trademark, and TeamWindows, ReportWindows and EditWindows are trademarks
exclusively used and licensed by Gupta Technologies.
The product described in this document is distributed under licenses restricting its use, copying, distribution, and
decompilation/reverse engineering. No part of this document may be reproduced in any form by any means without prior
written authorization of Gupta Technologies Corporation and its licensors, if any.
THE DOCUMENTATION IS PROVIDED “AS IS” AND ALL EXPRESS OR IMPLIED CONDITIONS,
REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE
EXTENT THAT SUCH DISCLAIMERS ARE HELD TO BE LEGALLY INVALID. GUPTA TECHNOLOGIES, INC.
SHALL NOT BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH THE
FURNISHING, PERFORMANCE, OR USE OF THIS DOCUMENTATION. THE INFORMATION CONTAINED IN
THIS DOCUMENTATION IS SUBJECT TO CHANGE WITHOUT NOTICE.
This document may describe features and/or functionality not present in your software or your service agreement. Contact
your account representative to learn more about what is available with this Gupta Technologies® product.
www.guptatechnologies.com
2
Table of Contents
3
Connection Strings ........................................................................................................................................................ 30
How to Edit SQL.INI ...................................................................................................................................................... 30
SQL.INI Keywords to Use ............................................................................................................................................ 31
Testing the Connection ........................................................................................................................................................ 31
Testing the Connection with SQLTalk .................................................................................................................... 31
Connecting to Sybase ........................................................................................................................................................... 32
Connecting to Oracle ............................................................................................................................................................ 32
Modifying the Registry ................................................................................................................................................ 32
Creating Views ................................................................................................................................................................ 32
Accessing tables and stored procedures on Oracle 8 and 9 ................................................................. 32
Running a view script........................................................................................................................................... 33
Specifying the Database in Your Application.............................................................................................................. 33
Troubleshooting Problems ................................................................................................................................................ 33
Problems Connecting ................................................................................................................................................... 33
Truncation of LONG Data ............................................................................................................................................ 34
Logging ODBC API Calls............................................................................................................................................... 34
Checking the Release Notes ....................................................................................................................................... 34
Contacting Technical Support ................................................................................................................................... 34
Selected Errors and Ways to Fix Them ................................................................................................................. 35
Sample Applications ............................................................................................................................................................. 36
Microsoft SQL Server .................................................................................................................................................... 36
Oracle .................................................................................................................................................................................. 37
Sybase System 11.x........................................................................................................................................................ 37
Chapter 3 – Connecting to Informix ..................................................................................................................... 38
Chapter Contents ................................................................................................................................................................... 38
Arithmetic Functions............................................................................................................................................................ 38
Autocommit.............................................................................................................................................................................. 39
Cursor Context Preservation ............................................................................................................................................. 39
Cursors ....................................................................................................................................................................................... 39
Data Types ................................................................................................................................................................................ 39
DDL Statement Support ...................................................................................................................................................... 40
Empty Strings .......................................................................................................................................................................... 40
GET DIAGNOSTICS Statement .......................................................................................................................................... 40
Isolation Levels ....................................................................................................................................................................... 41
Lock Time-Out......................................................................................................................................................................... 41
Miscellaneous Features ....................................................................................................................................................... 41
4
Positioned Updates ............................................................................................................................................................... 41
SET Statement Support ....................................................................................................................................................... 42
SQL.INI Keywords .................................................................................................................................................................. 42
buffrow............................................................................................................................................................................... 42
comdll ................................................................................................................................................................................. 43
defconnect......................................................................................................................................................................... 43
log ......................................................................................................................................................................................... 43
longbuffer .......................................................................................................................................................................... 44
remotedbname................................................................................................................................................................ 44
yieldonservercall............................................................................................................................................................ 45
Stored Procedures ................................................................................................................................................................. 45
Creating Stored Procedures ....................................................................................................................................... 46
Executing Stored Procedures .................................................................................................................................... 46
Dropping Stored Procedures..................................................................................................................................... 46
More information on stored procedures ...................................................................................................... 47
Storing TEXT and BYTE Data ............................................................................................................................................ 47
Unicode ...................................................................................................................................................................................... 47
Supported Data types........................................................................................................................................................... 48
Chapter 4 – Connecting to Microsoft SQL Server ............................................................................................. 49
Autocommit.............................................................................................................................................................................. 49
Cursor Context Preservation ............................................................................................................................................. 49
Data Types Supported.......................................................................................................................................................... 49
Identity Column Type................................................................................................................................................... 51
Empty Strings .......................................................................................................................................................................... 51
Isolation Levels ....................................................................................................................................................................... 51
Keywords as Table and Column Names ........................................................................................................................ 52
Lock Time-Out......................................................................................................................................................................... 52
Native Connectivity ............................................................................................................................................................... 52
Positioned Updates ............................................................................................................................................................... 52
Result Set Mode ...................................................................................................................................................................... 53
SET Statement ......................................................................................................................................................................... 53
SqlDirectoryByName Semantics ...................................................................................................................................... 53
SQL.INI Keywords .................................................................................................................................................................. 53
buffrow............................................................................................................................................................................... 54
comdll ................................................................................................................................................................................. 54
log ......................................................................................................................................................................................... 54
5
longbuffer .......................................................................................................................................................................... 55
odbctrace ........................................................................................................................................................................... 56
odbctracefile .................................................................................................................................................................... 56
remotedbname................................................................................................................................................................ 56
Stored Procedures ................................................................................................................................................................. 57
Creating Stored Procedures ....................................................................................................................................... 57
Deleting Stored Procedures ....................................................................................................................................... 57
Executing Stored Procedures .................................................................................................................................... 58
Example Code .................................................................................................................................................................. 58
Error Codes for Stored Procedures ........................................................................................................................ 59
SAL Extensions................................................................................................................................................................ 59
OdrExecuteProc .............................................................................................................................................................. 59
OdrGetNextResults ........................................................................................................................................................ 60
OdrGetReturnStatus ..................................................................................................................................................... 61
OdrPrepareProc.............................................................................................................................................................. 61
OdrPrepareNextResults .............................................................................................................................................. 62
Restrictions on Stored Procedures ......................................................................................................................... 63
Disable result set mode ....................................................................................................................................... 63
No scrollable cursors ............................................................................................................................................ 63
No positioned updates ......................................................................................................................................... 63
No output values .................................................................................................................................................... 64
Retrieving Output Parameters from Stored Procedures................................................................................ 64
Chapter 5 – Connecting to Oracle .......................................................................................................................... 66
Autocommit.............................................................................................................................................................................. 66
Cursor Context Preservation ............................................................................................................................................. 66
Data Types ................................................................................................................................................................................ 67
DBA Authority ......................................................................................................................................................................... 67
OS Authentication .................................................................................................................................................................. 67
Dynamic PL/SQL .................................................................................................................................................................... 68
Empty Strings .......................................................................................................................................................................... 68
Isolation Levels ....................................................................................................................................................................... 68
Lock Time-Out......................................................................................................................................................................... 69
Optimizing Message Traffic ............................................................................................................................................... 69
Positioned Updates ............................................................................................................................................................... 69
Result Set Mode ...................................................................................................................................................................... 69
SQL.INI Keywords .................................................................................................................................................................. 69
6
comdll ................................................................................................................................................................................. 70
fetchrow ............................................................................................................................................................................. 70
log ......................................................................................................................................................................................... 70
longbuffer .......................................................................................................................................................................... 71
nodefparse ........................................................................................................................................................................ 72
remotedbname................................................................................................................................................................ 72
substitute .......................................................................................................................................................................... 73
uselob.................................................................................................................................................................................. 73
Stored Procedures ................................................................................................................................................................. 74
Overloading Stored Procedures ............................................................................................................................... 75
SqlPLSQLCommand ...................................................................................................................................................... 75
Example PL/SQL stored procedure ................................................................................................................ 75
Executing the Sample Stored Procedure .............................................................................................................. 76
Dynamic Array Support for PL/SQL Stored Procedures ................................................................................ 76
Dynamic Arrays as INPUT arguments ........................................................................................................... 77
Uninitialized values ............................................................................................................................................... 77
Dynamic Arrays as OUTPUT arguments ....................................................................................................... 77
Uninitialized values ............................................................................................................................................... 77
Dynamic Arrays as INPUT/OUTPUT arguments ....................................................................................... 77
Transactions, Disconnects, and Exits............................................................................................................................. 77
Writing RAW Data ................................................................................................................................................................. 78
Chapter 6 – Connecting to Sybase .......................................................................................................................... 79
Autocommit and Chained Transactions ....................................................................................................................... 79
Bind Variables ......................................................................................................................................................................... 79
COMPUTE Clause ................................................................................................................................................................... 80
Cursor Context Preservation ............................................................................................................................................. 80
Data Types ................................................................................................................................................................................ 81
Using the Timestamp Data Type.............................................................................................................................. 81
Empty Strings .......................................................................................................................................................................... 82
Error Processing .................................................................................................................................................................... 82
Error Precedence ........................................................................................................................................................... 82
RAISERROR ...................................................................................................................................................................... 83
Retrieving Error and Info Messages ....................................................................................................................... 83
SybGetClientMsgCount ................................................................................................................................................ 83
SybGetClientMsg ............................................................................................................................................................ 84
SybGetNextClientMsg ................................................................................................................................................... 84
7
SybGetServerMsgCount ............................................................................................................................................... 85
SybGetServerMsg ........................................................................................................................................................... 85
SybGetNextServerMsg.................................................................................................................................................. 86
Examples ................................................................................................................................................................... 86
Getting Multiple Connections ........................................................................................................................................... 87
Handles and Connections ................................................................................................................................................... 87
Isolation Levels ....................................................................................................................................................................... 87
Positioned Updates ............................................................................................................................................................... 88
Positioned Updates and fetchrow ........................................................................................................................... 89
Releasing Locks ...................................................................................................................................................................... 89
Reserved Strings .................................................................................................................................................................... 89
SQL.INI Keywords .................................................................................................................................................................. 90
checkexists........................................................................................................................................................................ 90
closecursorateof ............................................................................................................................................................. 90
comdll ................................................................................................................................................................................. 91
enablemultipleconnections ....................................................................................................................................... 91
fetchrow ............................................................................................................................................................................. 92
locktimeout ...................................................................................................................................................................... 92
log ......................................................................................................................................................................................... 93
longbuffer .......................................................................................................................................................................... 94
remotedbname................................................................................................................................................................ 94
substitute .......................................................................................................................................................................... 95
sybapplicationname...................................................................................................................................................... 95
sybautocommit ............................................................................................................................................................... 96
sybmaxmessages............................................................................................................................................................ 96
sybtracefile ....................................................................................................................................................................... 97
sybworkstationname.................................................................................................................................................... 97
yieldonservercall............................................................................................................................................................ 97
Stored Procedures ................................................................................................................................................................. 99
Using Cursors with Stored Procedures ................................................................................................................. 99
SybExecuteProc ........................................................................................................................................................... 100
SybExecuteProcEx ...................................................................................................................................................... 101
SybGetNextResults ..................................................................................................................................................... 102
SybGetReturnStatus ................................................................................................................................................... 102
SybPrepareProc ........................................................................................................................................................... 103
SybPrepareNextResults ............................................................................................................................................ 104
8
Retrieving Output Parameter Values .................................................................................................................. 104
Transactions, Disconnects, and Exits.......................................................................................................................... 106
Writing and Retrieving IMAGE and TEXT Data ...................................................................................................... 106
Writing Data .................................................................................................................................................................. 106
Retrieving Data and Buffer Size ............................................................................................................................ 107
SybWriteText ................................................................................................................................................................ 107
Chapter 7 – Connecting to Databases Using ODBC ....................................................................................... 110
Connecting to Specific Data Sources ........................................................................................................................... 110
Connecting to Access ................................................................................................................................................. 110
Connecting to DB2/400 ........................................................................................................................................... 111
About the ODBC Driver for SQLBase ................................................................................................................... 111
Brand Information.............................................................................................................................................................. 111
Cursor Context Preservation .......................................................................................................................................... 112
Data Types ............................................................................................................................................................................. 112
Error Processing ................................................................................................................................................................. 112
Error Code Mapping .......................................................................................................................................................... 113
Lock Time-Out...................................................................................................................................................................... 117
SQL.INI Keywords ............................................................................................................................................................... 117
buffrow............................................................................................................................................................................ 117
comdll .............................................................................................................................................................................. 118
enablemultipleconnections .................................................................................................................................... 118
log ...................................................................................................................................................................................... 119
longbuffer ....................................................................................................................................................................... 119
odbctrace ........................................................................................................................................................................ 120
odbctracefile ................................................................................................................................................................. 120
remotedbname............................................................................................................................................................. 120
Stored Procedures .............................................................................................................................................................. 121
Transactions, Disconnects, and Exits.......................................................................................................................... 121
Chapter 8 – Connecting to Multiple Databases Concurrently .................................................................. 123
Overview ................................................................................................................................................................................ 123
Two Approaches.................................................................................................................................................................. 123
About the Application ............................................................................................................................................... 123
Schema and Location of Tables ............................................................................................................................. 124
Running the Application .................................................................................................................................................. 124
Preparing to Run the Application......................................................................................................................... 124
Configuring the Application ................................................................................................................................... 125
9
Connecting to the Servers ....................................................................................................................................... 125
Starting the sample application .................................................................................................................... 125
Logging in to the database servers .............................................................................................................. 125
Populating the Tables ................................................................................................................................................ 126
Deleting the Tables ..................................................................................................................................................... 126
Displaying Table Data................................................................................................................................................ 126
About the Details Form............................................................................................................................................. 127
Modifying Autocommit and Isolation Level Settings ................................................................................... 127
Disconnecting and Exiting....................................................................................................................................... 128
Design Issues ........................................................................................................................................................................ 128
Connecting to the Databases .................................................................................................................................. 128
Setting autocommit .................................................................................................................................................... 129
Concurrency and Consistency ............................................................................................................................... 130
Locking .................................................................................................................................................................... 130
Isolation levels ..................................................................................................................................................... 131
Replicating Table Schemas and Data .................................................................................................................. 132
Displaying Table Data................................................................................................................................................ 135
Key Columns ................................................................................................................................................................. 136
Transaction Processing ............................................................................................................................................ 136
Processing the INVOICE Transaction .................................................................................................................. 138
Dynamic Binding ......................................................................................................................................................... 138
Implementation Details.................................................................................................................................................... 139
Updating Table Data .................................................................................................................................................. 140
Dynamic Table Windows Management ............................................................................................................. 140
Microsoft SQL Server and SQLBase ............................................................................................................. 140
Oracle ....................................................................................................................................................................... 140
Dynamic Data Type Binding ................................................................................................................................... 141
Oracle ....................................................................................................................................................................... 141
Microsoft SQL Server ......................................................................................................................................... 141
Isolation Levels and Oracle ..................................................................................................................................... 141
Autocommit ................................................................................................................................................................... 142
Getting More Information ............................................................................................................................................... 143
Glossary ....................................................................................................................................................................... 144
10
Chapter 1 –Overview
This chapter explains how to connect SQLWindows applications to database servers. It describes some of the
features supported by one or more of the databases to which you can connect a SQLWindows application.
Read this chapter to get a general description of each feature, and then read the chapter that covers the
database to which you are connecting to find out if (and how) those features are supported by that database.
If the chapter that discusses a particular database does not mention a particular feature, that feature is not
supported (either because the database does not support it, or because SQLWindows does not support it for
that database).
Client/Server Architecture
A SQLWindows client/server application consists at runtime of the following components:
• SQLWindows application—This is a program that performs services for the user, and that communicates
with a database using a SQLRouter. The application can be written using QuickObjects®, the object-
oriented Scalable Application Language (SAL), or a combination of both.
• SQLRouter—A software library supplied with Team Developer that takes as input data and actions
specified by a Gupta SQLWindows application; SQLRouter maps the input into appropriate function calls
and data types from a database vendor’s API (such as Oracle’s OCI or Microsoft’s ODBC) to implement the
specified actions on the given data.
SQLRouter also accepts data and actions from a database, and converts them into actions and data that a
SQLWindows application can understand.
You can use the following SQLRouters to connect to the following databases:
You can also use SQLRouter/ODBC to connect to any database for which you can obtain an ODBC driver
that is certified to work with SQLWindows. For more information about connecting using ODBC drivers,
see Chapter 7 – Connecting to Databases Using ODBC.
• Database vendor API —The call-level interface supplied by a database vendor to communicate with that
vendor’s database. Examples include Oracle OCI, Informix SQLI, Sybase CT-LIB, CA-OpenIngres Embedded
SQL, and Microsoft ODBC.
• Network access layer—The software library supplied by a database vendor to accept the actions and data
specified by the database vendor API and send them out over the network. This library also accepts
11
actions and data provided by the database over the network and passes them up to the database vendor
API layer.
• Network software—Software that sends and receives messages over network hardware. Examples
include TCP/IP, IPX/SPX, NetBEUI, NetBIOS, and Named Pipes.
Autocommit
Commit relates to the grouping of server actions (typically changes to a database) so all of the actions are
made permanent in the database if and only if they are all successful. The set of such actions constitutes a
transaction (see also Transactions on page 26).
The default setting for autocommit is:
• Oracle—OFF
• Informix—OFF
• Microsoft SQL Server—ON
• System 11—OFF
• CA-OpenIngres—OFF
• ODBC—In general, it depends on the driver and data source.
If autocommit is on, each SQL statement executed becomes its own transaction. Unless an error occurs, the
result of the SQL statement is committed to the database. Also, you release locks and other transaction
resources as soon as possible, without needing to execute an explicit COMMIT statement.
If autocommit is off and you have a pending transaction, what happens if you try to execute a DDL statement
depends on the database server:
• Microsoft SQL Server and Sybase—DDL statements are not allowed while a transaction is pending.
• Oracle—If you try to execute a DDL statement, the database server first commits the pending transaction
before executing the DDL statement.
• Informix—If you are using the ANSI or Transaction database server mode, DDL statements are considered
part of the current transaction. Once you commit (or roll back) the transaction, the DDL is committed (or
rolled back) along with all the other statements that make up the transaction.
• CA-OpenIngres—DDL statements are considered part of the current transaction. Once you commit (or roll
back) the transaction, the DDL is committed (or rolled back) along with all the other statements that
make up the transaction.
If autocommit is off, you start a transaction, then you try to turn autocommit on, what happens next depends
on the database server:
• Microsoft SQL Server, CA-OpenIngres, and Sybase—You get an error. You must first commit or roll back
the pending transaction before you can turn autocommit on.
• Oracle and Informix—You can execute the statement to turn autocommit on while a transaction is
pending, but the new setting for autocommit does not immediately take effect; you must first finish the
transaction by explicitly committing it or rolling it back. Once you finish the pending transaction,
autocommit takes effect.If autocommit is on and cursor context preservation (CCP) is off, performing an
SQL statement that modifies a row in a result set (such as UPDATE or DELETE) not only commits the
12
change to the database, it also destroys the result set and its associated cursor. To perform multiple
operations on the same result set, either disable autocommit or enable CCP (or both).
• If autocommit is off, you are responsible for:
• Executing the COMMIT statement (or calling SqlCommit) often enough to reduce unnecessary locking
that could restrict access to data for other users (because of either read or update locks).
• Grouping your changes to the database in such a way that only the appropriate changes are cancelled if
you need to execute a ROLLBACK.
An explicit commit (either manual or automatic) affects all SQL handles associated with the same connection
to the database.
To find out if the database you are connecting to supports autocommit, how it supports it, and whether
autocommit is on or off by default, read the chapter in this book devoted to that database.
To turn autocommit off for all SQLWindows applications that connect to a given database, set the appropriate
SQL.INI keyword (if one is defined for that database) to “off”.
Note: You can turn off autocommit only for some of the databases you can connect to. For more
information, see the Autocommit section of the chapters that discuss the databases your application
connects to.
You turn autocommit on or off by calling SqlSetParameter. Even though you specify a specific handle (hSql) as
one of the arguments, the change in the setting for autocommit affects all handles associated with the same
connection as hSql.
To turn autocommit off for a given application, include the following line in your Gupta SQLWindows
application:
Call SqlSetParameter(hSql, DBP_AUTOCOMMIT, FALSE, strNull)
If autocommit is off, changes you make to a database do not become permanent until you execute a COMMIT
statement (or call SqlCommit). Further, if you disconnect from the database or exit the application (either
normally or abnormally) without executing COMMIT, the pending transaction may or may not be committed
for you. To find out what does happen, read the chapter that covers the database you are connecting to.
For additional information, read the documentation on SqlSetParameter and DBP_AUTOCOMMIT in the
SQLWindows Function Reference.
Bind Variables
Bind variables, also called program variables, host variables, or parameter markers, refer to data values
associated with an SQL statement. Bind variables associate (bind) a syntactic location in an SQL statement
with a data value in that statement; the binding actually occurs at runtime.
A bind variable in an SQL statement indicates that data from a variable in the application is bound to it each
time the statement executes. This feature allows an SQL statement to be compiled once and executed
repeatedly with a new set of values in the bind variables each time.
Read the chapter that covers the database to which you are connecting to find out if (and how) bind variables
are supported by that database.
13
Concurrency
A single Gupta SQLWindows application can access multiple tables on a given database, as well as connect to
multiple databases simultaneously. However, execution of all Scalable Application Language (SAL) functions is
single-threaded— the function must complete (and the value of bOk returned to the application) before the
next statement or function in the application can be executed.
Concurrency can also be affected by how different applications obtain and release locks. For related
information, see “Isolation Levels” on page 19 and “Lock Time-Out” on page 21.
To learn how to write applications that connect to multiple databases concurrently, see Chapter 8 –
Connecting to Multiple Databases Concurrently.
Connectivity Parameters
In your Gupta SQLWindows application you can get and set a number of parameters that affect transaction
processing and other activities or attributes related to connectivity.
The following parameters can be retrieved with SqlGetParameter and set with SqlSetParameter:
• DBP_AUTOCOMMIT—Whether autocommit is on or off.
• DBP_BRAND—The vendor of the database you are connected to.
• DBP_LOCKWAITTIMEOUT—Time limit on waiting for a lock to be released.
• DBP_PRESERVE—Whether cursor context preservation is on or off.
• DBP_VERSION—The version of the database to which you are connected.
• DBP_ROLLBACKONTIMEOUT—Whether the most recent transaction is rolled back if a time-out expires.
• DBP_TIMEOUT—Specifies Sql command timeout. Works only in .NET applications
The library file SQLNWKCN.APL (in the Gupta installation directory) contains a large number of user constants
that you can retrieve with SqlGetParameterAll and set with SqlSetParameterAll. To use these constants,
include this file in your Gupta SQLWindows application. Open this file with File, Open from the Gupta
SQLWindows menu bar and expand the user constants section of the outline to see the constants defined.
For example, to set the size of the buffer used to hold LONG data to 2000 bytes, include the following line in
your application:
SqlSetParameterAll(hSql,DBP_LONGBUFFER,2000,’’,TRUE)
14
For multiple database connections to work, the order of connections in the [win32client.dll] section of the
sql.ini must follow this convention:
• If not using SQLBase or ODBC, these entries may appear in any order.
• If you're using ODBC and specifying multiple routers, sqlodb32 should appear in the last position.
• If you're using SQLBase and specifying multiple routers, sqlws32 should be the last position.
• If you're using SQLBase & ODBC and specifying multiple routers, sqlodbc32 should be in the 2nd last
position and sqlws32 in the last position.
The following is an example:
[win32client.dll]
comdll=sqlsyb32 ! Sybase native router.
comdll=sqlora32 ! Oracle native router.
comdll=sqlodb32 ! ODBC is in the 2nd last position.
comdll=sqlws32 ! SQLBase is in the last position.
If a remotedbname statement is found that lists a name matching the name of the target database, the
application tries to connect. If the attempt to connect fails, the application gets an error.
If no remotedbname statement is found that lists a name matching the name of the target database, the
router-specific section for the next SQLRouter in the sequence of comdll statements is searched. This
continues until a matching database name is found, or until the sequence of comdll statements is exhausted.
A slight variation applies to SQLRouter/ODBC and SQLRouter/Microsoft SQL Server. Instead of searching the
[odbcrtr] section of SQL.INI for a remotedbname statement, the application tries to find an ODBC data source
name in the ODBC.INI file that matches the target database name. Otherwise, the processing is the same as
for all the other SQLRouters.
For more information about the SQL.INI file, see “Initializing SQLWindows Applications” on page 28. For more
information about the remotedbname statement, read the SQL.INI keywords section for each of the database
servers (Oracle, Informix, and so on) you will connect to.
15
Call SqlSetParameter(hSql, DBP_PRESERVE, TRUE, strNull)
in your SQLWindows application. Call this function for each SQL handle associated with the result sets you
want to maintain context for (see “Handles, Contexts, and Connections” on page 17).
If your application performs a ROLLBACK, all result sets (whether backend result sets or FERS) and their
cursors are discarded even if CCP is enabled.
If you are using front end result sets (FERS) and you have enabled CCP, the rows in the result set remain
available to your application even after you execute a COMMIT. However, the data in the FERS file is not
updated to keep it in sync with any changes made to the corresponding rows on the database server. If other
clients make changes to the table on the server, the FERS data will be out of date. To learn more about FERS,
see “Front End Result Sets”, which follows.
To find out if the database you are connecting to supports CCP, read the chapter in this book that covers that
database.
If you turn on result set mode, and your application is connected to a database that has native support for
scrollable cursors (sometimes called backend result sets or backend cursors), SQLWindows uses that support
to allow the user to scroll in both directions through a result set. If the database does not have native support
for scrollable cursors, SQLWindows implements this capability using front end result sets (FERS).
Even if the target database supports (backend) scrollable cursors, this feature must first be enabled on the
database for your application to use it.
To implement FERS, the SQLRouter software takes a snapshot of the result set returned by a SELECT
statement and stores it in a temporary file on the client. Each file is named FRSn (with no extension), where n
is a positive integer. The first file is named FRS1, the second is named FRS2, and so on.
SQLRouter needs two file handles for every FERS file it creates. If SQLRouter cannot obtain the file handles, it
returns an error to the application.
These FERS files are deleted when your SQLWindows application attempts to prepare another SQL statement
or disconnects from the database server. If the application ends abnormally and leaves these files, you must
delete them manually. Look for them in the standard directory where temporary files are stored.
Note: If your application is using FERS, you can release all shared locks on the result set returned by your
SELECT statement, call SqlGetResultSetCount. To learn more about this function, see the SQLWindows
Function Reference.
You cannot SELECT...FOR UPDATE (use positioned cursors) if the named cursor is associated with a front end
result set. In other words, you cannot lock on the server the rows that are being displayed on the client. The
16
data the user sees on the client may not match the data on the server if another application makes changes
to those same rows.
For information on result set mode and how to enable it, see “Result Set Mode” on page 24. For information
on FERS and cursor context preservation (CCP), see “Cursor Context Preservation” on page 15.
Note: Some Gupta documentation refers to the SQL handle as a “cursor.” This is very different from the ANSI
use of the term cursor, which is a pointer to a given row in a result set.
In general, a SQLWindows application that uses multiple handles does one of the following:
• Connects to the same table for two different activities—the first handle is used to prepare and execute a
SELECT statement to obtain a result set, then fetch the desired row from that result set; the second
handle is used to prepare and execute the SQL statement that modifies the result set (UPDATE, INSERT, or
DELETE).
• Connects to two different tables—the handle is used to prepare and execute the SQL statement that
updates a column in one table based on a value from another table obtained by preparing and executing
a different SQL statement.
• Connects to two different databases—each handle identifies a separate context for preparing and
executing SQL statements.
In general, different SQL handles, while they identify separate contexts for preparing and executing SQL
statements, are all part of the same transaction scope. Therefore, if you execute a COMMIT or ROLLBACK
statement on any handle, the database server commits (or rolls back) the results of all of the uncommitted
SQL statements executed on all of the open handles connected to a given database.
Note: When it comes to committing statements, some databases distinguish between Data Manipulation
Language (DML) statements and Data Definition Langauge (DDL) statements. With these databases,
DDL statements are always committed, whereas DML statements are committed only if the COMMIT
statement (or the SqlCommit function) is executed. In other databases, neither DML nor DDL
17
statements are committed until COMMIT is executed (or SqlCommit is called). This whole discussion
assumes, of course, that autocommit is off.
The maximum number of handles and connections your application can have depends on your client
operating system resources and any limits imposed by the target database server— SQLWindows itself
imposes no limitations.
For related information, see “Transactions” on page 26.
Note: The numeric value to use as the second parameter is 23 (for LONG BINARY). To make your code self-
documenting, you should create a symbolic constant with that value, and then use the constant as
the parameter.
For example:
Constants
System
User
18
Number: LONGBINARY = 23
Local Variables
String: strName
Long String: strPhoto
...
Actions
...
SqlConnect(hSql)
...
! Assume we have read a name into strName and a .BMP file
! into strPhoto. We want to update a particular employee’s
! photo in the database.
Call SqlPrepare(hSql, ’UPDATE emp ’ ||
’SET emp_name = :strName,image_col = :strPhoto’ )
SqlSetLongBindDatatype should be called immediately after the call to SqlPrepare. The binding established
with SqlSetLongBindDatatype lasts until the next call to SqlPrepare on the same SQL handle.
SQLWindows automatically converts between LONG STRING and TEXT data. You do not need to call
SqlSetLongBindDatatype when reading and writing TEXT data.
Isolation Levels
Isolation levels control how access to the tables in a database by one user affects other users accessing the
same tables in that database. These isolation levels are implemented by locks and apply to all SQL statements
executed as part of a single transaction.
The isolation level you choose depends on the application’s requirement for consistency and concurrency.
Consistency means that during a transaction, the data read remains stable. This implies that the data being
read by one transaction does not change because of updates, deletes, and inserts performed by other
transactions.
Concurrency is a function of the number of users that can access data at the same time. High concurrency
allows multiple users to execute database transactions simultaneously without interfering with each other,
but at the possible expense of consistency.
19
• phantom row — Transaction A performs a SELECT on a table. Based on the selection criteria in the
SELECT statement, a set of rows is returned to A. Transaction B inserts one or more new rows into the
same table with values that happen to match the selection criteria of the SELECT statement used by A. If
transaction A re-executes the same SELECT statement, it obtains a different set of rows than it did the
first time.
Note: This discussion applies to Gupta applications. If using SQLTalk, the default isolation level, irrespective
of the database to which you connect, is always RR (repeatable reads).
Choose the appropriate isolation level for your applications depending on the balance you need to achieve
between data access concurrency and data consistency.
RL not supported committed reads read committed not supported not applicable
Default is not an actual code. This row indicates the isolation level you get when you first connect to the given
database server.
Microsoft SQL Server supports the isolation levels listed in the column Microsoft SQL Server/ODBC. For ODBC
data sources on other than Microsoft SQL Server, the SQLWindows ODBC router attempts to set the very
same mapping of two-letter codes to isolation levels; however, which isolation level (if any) is actually
implemented for a given code depends on the ODBC driver and the database server you are using to access
your data source. Your ODBC driver and database server documentation should provide the information you
need.
CA-OpenIngres servers do not support isolation levels. Use the SET LOCKMODE statement to set different
types and levels of locks. The default lock is Shared for read and Exclusive for write.
If you try to change isolation levels while a transaction is pending, what happens depends on the database
server:
• Oracle—The attempt to change isolation levels is ignored.
• Informix and Microsoft SQL Server—The pending transaction is first committed, then the isolation level is
changed as requested.
• Sybase System 11—The request is rejected and an error is raised.
20
To set the isolation level in your application, call SqlSetIsolationLevel. For example, to set the isolation level to
SQL_TXN_SERIALIZABLE on Microsoft SQL Server 6.0, put the following statement in your SQLWindows
application:
Call SqlSetIsolationLevel(hSql,’RR’)
See the SQLWindows Function Reference for more information about this function.
To find out the kinds of isolation levels supported on the databases you are connecting to and the
appropriate arguments to use when calling SqlSetIsolationLevel, see the chapter for those databases.
Lock Time-Out
Lock time-out is the amount of time spent waiting for a resource to become available. If an action cannot be
completed within the set limit, the transaction is aborted and any changes are rolled back.
To enable lock time-out, call SqlSetLockTimeout, or call SqlSetParameter with the DBP_LOCKWAITTIMEOUT
parameter. (For more information about these functions, refer to the SQLWindows Function Reference and
the on-line help.)
Read the chapter that covers the database to which you are connecting to find what kind of lock time-outs (if
any) are supported on that database.
21
databases store different values in a (varying length) character string column when you try to store the empty
string—some do store the empty string, some store NULL, and others store a space.
When inserting or updating a string column in a database table in such a way as to indicate that there is no
data in the column, you typically enter a NULL (if the table allows this), the empty string (also called the zero-
length string), or a space. Which of these you values you use depends on whether the table allows NULLs in
the column and how your application is written.
The value that is actually stored in the database, depending on the database server and the value supplied by
the client, is the following:
To use STRING_Null, you must assign it to a String variable, then use that variable as a bind variable in your
SQL INSERT or UPDATE statement.
The behavior of an ODBC data source depends on the driver and the database server you connect to.
Using NULL
To insert NULL into any of the string columns of your database tables, or to update such columns with NULL
(assuming the columns allow NULLs), you must do the following:
1. Set a String variable to the predefined constant STRING_Null.
2. Prepare and execute a SQL INSERT or UPDATE statement using the variable in step 1 as a bind variable;
for example:
Set strVar = STRING_Null
. . .
SqlPrepareAndExecute(hSql, `UPDATE my_table SET this_column = :strVar`)
You must explicitly set the String variable to STRING_Null because SQLWindows initializes all String variables
to the empty (zero-length) string. Only by using a bind variable set to STRING_Null (rather than the empty
string) can you store NULL in the string columns of your database tables.
To test whether a string column value you fetch from one of the tables in your database is NULL, you must
compare the variable into which you fetched the value to the constant STRING_Null; for example:
SqlPrepareAndExecute(hSql, `SELECT string_col FROM my_table INTO
:strColValue`)
IF strColValue = STRING_Null
. . .
You can also hard-code the NULL in a SQL statement, if appropriate.
22
Positioned Updates
SQLWindows applications can perform positioned updates (WHERE CURRENT OF cursor updates) when
connected to certain databases. For positioned updates to be possible:
• You must create a unique index on one of the table columns (Microsoft SQL Server only).
• You must turn on result set mode (scrollable cursors), except that this is not required for Oracle.
Note: You need to execute the CREATE UNIQUE INDEX statement (included in the code below) only when
connected to Microsoft SQL Server version 6.x. For other databases, omit this statement.
Call SqlConnect(hSqlA)
Call SqlConnect(hSqlB)
Set strCreateTable = ’CREATE TABLE REALTY ’
Set strCreateTable = strCreateTable || ’(PROPNUM INT,’
Set strCreateTable = strCreateTable || ’CITY VARCHAR(30),’
Set strCreateTable = strCreateTable || ’PRICE numeric_data_type)’
Call SqlPrepareAndExecute(hSqlA, strCreateTable)
Set strCreateIndex = ’CREATE UNIQUE INDEX REALTY_IDX ’
Set strCreateIndex = strCreateIndex || ’ON REALTY(PROPNUM)’ Call
SqlPrepareAndExecute(hSqlA, strCreateIndex)
Call SqlSetResultSet(hSqlA, TRUE)
Call SqlPrepareAndExecute(hSqlA, ’SELECT PROPNUM, CITY, PRICE
FROM REALTY
FOR UPDATE
INTO :COL1,:COL2,:COL3’)
If NOT SqlOpen(hSqlA, ’CUR1’)
…
If NOT SqlFetchNext(hSqlA, nRetVal)
…
If NOT SqlPrepare(hSqlB, ’UPDATE REALTY
23
SET PRICE =:COL3
WHERE CURRENT OF CUR1’)
…
! If no problem preparing the UPDATE statement, do it.
Else Call SqlExecute (hSqlB)
To find out if the database you are connecting to supports positioned updates, see the chapter for that
database.
Initial setting
When a SQLWindows application first starts up, the value of the global system variable SqlResultSet is
undefined (null). As long as the variable's value remains undefined, result set mode is initially on for all your
connections to SQLBase and initially off for all your connections to all other database servers.
24
If you set SqlResultSet to TRUE, result set mode is initially on for any subsequent connection you make to
any database server, including SQLBase. If you set SqlResultSet to FALSE, result set mode is initially off for
any subsequent connection you make to any database server, including SQLBase. In either case, if you then
set SqlResultSet to NUMBER_Null, result set mode is initially on for all your subsequent connections to
SQLBase and initially off for all subsequent connections to all other database servers.
Changing the value of the global variable SqlResultSet does not affect the setting of result set mode for any
existing connection. To change the setting of an existing connection, you must call the function
SqlSetResultSet.
With Microsoft SQL Server 6.x or any ODBC data source, even though you specify a specific SQL handle as an
argument to SqlSetResultSet, the new setting for result set mode affects all SQL handles on the same
connection, not just the SQL handle you pass as an argument. If you connect natively to Oracle, Informix, or
Sybase System 11, however, the new setting for result set mode affects only the handle you specify as an
argument to SqlSetResultSet.
*When connected to Sybase System 11, you can declare a cursor on a stored procedure and fetch rows from a
result set returned by that stored procedure, but you cannot do positioned updates or deletes on the result
set using that cursor.)SQL.INI Keywords.
25
All SQLWindows applications initialize themselves by reading the SQL.INI file. To find out more about this file,
see “Initializing SQLWindows Applications” on page 28.
Stored Procedures
Most databases allow procedures containing SQL statements and procedure logic to be compiled and
executed on the database server. These procedures can return result sets, and some can accept input bind
variables (host variables) as arguments. If the target database supports stored procedures, you can call them
from a SQLWindows application.
Using stored procedures can improve application performance by reducing network traffic and executing
compiled SQL operations on the server. Because stored procedures are compiled, the execution plans are
stored in a system table; this allows the stored procedure to execute very quickly. Stored procedures can
enhance security by acting as a controlled access point to sensitive data. They can also increase the
robustness and reliability of distributed processing by centralizing critical or core application logic in one
location (the server).
Depending on the database server you are connecting to, you may be able to pass input arguments, retrieve
values in output arguments, retrieve a result status from the stored procedure, and retrieve result sets. In
some cases you may be able to specify input arguments and retrieve output arguments using bind variables.
Read the chapter that covers the database to which you are connecting to find out if that database supports
stored procedures, how to call them, and any other information specific to that database’s support for stored
procedures.
Transactions
A transaction is a set of actions on a database that are treated atomically—all of the actions are made
permanent in the database or none of them are. Normally, you make all the actions permanent by preparing
and executing the COMMIT statement (or calling SqlCommit); if you want to abandon all the actions (undo
them), you prepare and execute the ROLLBACK statement.
There is no SAL function that corresponds to SqlCommit. To roll back a transaction, you prepare and execute
the ROLLBACK statement. For example:
SqlPrepareAndExecute(hSql,’ROLLBACK’)
Each COMMIT or ROLLBACK statement defines a new transaction boundary; all the statements whose actions
are made permanent with COMMIT (or undone with ROLLBACK) are part of the transaction scope.
For additional information, see “Autocommit” on page 12 and “Handles, Contexts, and Connections” on page
17.
26
Chapter 2 – Initializing and Testing Your
Connection
This chapter describes how to connect a SQLWindows application to a database, test the connection, and
configure the initialization of the client.
Synopsis of What to Do
1. Install your network protocol software (such as TCP/IP, NetBIOS, NetBEUI, Named Pipes, or IPX/SPX) and
the client-side software supplied by your database vendor (network access layer software, API library,
and client tools and utilities). Follow the instructions in the documentation provided with those products.
2. Verify that you can connect to your target database using a suitable tool provided by your database or
other vendor. If you need help, talk to your network or database administrator. Some of the tools
available are the following:
Informix—ILogin.exe
Oracle—SQL*Plus (if you have a sufficiently recent version of the database), Sample Pro C application
CA-OpenIngres—Terminal Monitor
Microsoft SqlServer—ISQL/w
Sybase—SQL Advantage
3. Install SQLWindows and choose the appropriate SQLRouters for the databases you will be connecting to.
4. Configure the target data source. (This applies only if you are connecting using ODBC.)
5. Configure the initialization of SQLWindows by editing the SQL.INI file appropriately.
6. Verify that you can connect to the target database using Team Developer software by running SQLTalk
for Windows.
Additional information on steps 4 through 6 is provided after the next section.
Before Connecting
Here are some things to check out before trying to connect a SQLWindows application to a database:
• On the client machine:
a. Make sure all the software components listed in the Release Notes are installed on the client
computer.
b. Verify that you can connect to the target database using the appropriate tools provided by the
database vendor. Read the documentation supplied by the vendor to learn about such tools and how
to use them to verify the connection between your client and the database.
c. Check that the SQL.INI file contains the appropriate statements, and that the keyword values are
specified correctly. To learn more about this, read the rest of this chapter, then read the chapters that
cover the databases you are connecting to.
• On the server machine:
27
a. Check that the appropriate network software is running.
b. Be sure the database server is running and that the target database has been created.
c. Verify that you have a user account with the correct privileges on the database.
Consult with your database administrator and network administrator for any additional help you might need.
Note: Do not edit the ODBC.INI file directly. Use the ODBC Administrator to make any changes to your list of
ODBC data sources. Also, check the documentation that comes with your ODBC driver to see if your
ODBC driver vendor also supports other ways of modifying the ODBC.INI file.
28
If you installed other Gupta Technologies products on your machine, a configuration file already exists. If you
install SQLWindows in the same directory as the other Gupta Technologies products, the installation program
adds new statements or modifies existing statements in the file.
Note: All statements from the old SQL.INI file are carried over into the new one.
Note: Although Team Developer 3.1 and later allows the existence of multiple configuration files on a single
machine, you should still be cautious when you have multiple files. The most common cause of
connectivity difficulties is an application connecting to one configuration file when the developer
believes it is connecting to a different file. Understand the search sequence above and be certain that
your application is finding the right file.
Connection Strings
In Team Developer 5.2, the [ConnectionStrings] section was introduced to the SQL.INI file, and the following
functions were added to Team Developer:
• SqlWriteConnectionString
• SqlGetConnectionStrings
• SqlDeleteConnectionString
• SqlListConnections
See the online help for detailed documentation of these functions. A connection string is formatted as
follows:
alias=<alias>;comdll=<comdll>;settings=<settings>
Here are some examples:
[ConnectionStrings]
comdll=sqlodb32;alias=Sql Server Standard ODBC;dbname=qa2k3odbc
comdll=sqlsyb32;alias=Robby Sybase;dbname=Robby2;database=master
comdll=sqlifx32;alias=Robby;host=robby;dbname=sysutils
comdll=sqlora32;alias=QAOra10G Our favorite Oracle DB;dbname=qaora10g
comdll=sqlodb32;alias=My DB 2 Connection;dbname=DB2ODBC
30
• Put each statement on one line. Inserting carriage returns or any “end-of-line” markers in the statement
can cause errors.
• Put comments on their own lines rather than placing comments on the same lines as keyword
statements. Use a semi-colon (;) as the first character of the comment line.
A SQLWindows application reads the SQL.INI only when it initializes. To force an application to see any
changes you make to the file, you must stop or exit from all Gupta software running on the client (including
SQLWindows and all running applications created with SQLWindows), then restart the application.
31
Connecting to Sybase
You do not need to run catalog view scripts before running your SQLWindows applications against Sybase
System 11.x and higher, because SQLRouter/Sybase can access the system catalog directly whenever
necessary.
However, you need to obtain suitable privileges for each Sybase database you will connect to before you can
run SQLWindows or an application you create with SQLWindows.
For each such database:
1. Log in as a user who has System Administrator privileges.
2. Run the program SYBPRIVS.EXE (located in the Gupta installation directory).
Connecting to Oracle
To connect to Oracle, you may have to make certain changes to your Windows Registry. You must also create
certain views to access tables and to run stored procedures.
Oracle version 9.x does not require any modifications to the Registry.
Creating Views
Before you can access tables on Oracle you must run the appropriate views script. You must also run a specific
views script to be able to execute stored procedures on Oracle.
32
Running a view script
1. Start SQLTalk from the Gupta Team Developer group in the Program menu, or by running the executable
file sqltalk.exe in the Gupta installation directory.
2. Select Session,Connect from the menu bar. Fill in the dialog box with the appropriate information.
3. Once you are connected, click Close.
4. Select File, Open from the menu bar.
5. In the File of Type selection box, select All Files (*.*).
6. Select the file VIEW8.ORA (or PLSVIEW8.ORA) in the Gupta installation directory if using Oracle8. Select
the file VIEW7.ORA (or PLSVIEW7.ORA) if using Oracle7.
7. Select Session, Execute Script from the menu bar. Let the script run to completion. (Ignore any error
messages about tables being dropped.)
8. Select File, Exit from the menu.
For more information on how to use SQLTalk, read the Gupta online help topics for SQLTalk.
Troubleshooting Problems
This section discusses some of the problems that can arise when connecting SQLWindows applications to
your database and possible ways to resolve them. It also has a table of some of the errors you may encounter
when running SQLWindows applications along with suggestions for fixing them.
Problems Connecting
When a SQLWindows application initializes, it reads the SQL.INI file. When the application reads the
[win32client.dll] section of that file, it loads all the DLLs specified in the comdll statements.
The application tries to connect to the database by calling the appropriate function in each DLL loaded. If the
DLL finds the requested database, it issues a database connect request. If the DLL gets no response, it returns
the “failure to connect” error to the application, which then calls the appropriate function in the next DLL
that was loaded. This continues until either a connection is established or all the DLLs have been tried.
If you have trouble connecting your SQLWindows application to your target database:
33
1. Check with your database administrator that the target database is running.
2. Verify that you can connect to the database from your client machine, first with native client database
tools (or equivalent), then with SQLTalk for Windows.
3. Read the section on searching for SQL.INI earlier in this chapter. If necessary and practical, temporarily
rename other copies of SQL.INI so that your desired copy is the only one with the original name. Don’t
forget to reverse the renaming process after you have determined the source of the trouble.
If you have multiple SQL.INI files on your machine (which is possible if you install different Gupta
Technologies products into different directories), the file you modify might not be the one being used at
initialization time. Check the order in which directories are searched for the SQL.INI file (see “Search Path
for SQL.INI” on page 29).
4. Check that the appropriate comdll statements appear in the [win32client.dll] section of the SQL.INI file.
(Read the SQL.INI keywords section in each chapter that discusses a database to which you are
connecting for more information about the comdll keyword.)
5. Check that you configured your remotedbname statements correctly. (This step does not apply if you are
connecting to your database using ODBC.)
111 — SQL Application has re-entered the library Check for any re-entrancy (for
application interface SQLWNTM.DLL while waiting for a example, SAM_Timer messages
recursively entered. server request. SQLWNTM.DLL is re- during asynchronous operations)
entrant only from different and disable them during server
applications. requests.
135 — Invalid cursor A SQL handle was passed to a function Establish a valid connection before
handle. before a valid connection was passing a SQL handle to a function.
established.
201 — No compiled The application is attempting to Compile SQL statements before
command. perform an operation, and either it has executing them.
not compiled an SQL statement, or no
statement exists any longer (for
example, because a ROLLBACK was
executed).
203 — Invalid SQL You constructed an SQL statement with Check the syntax of your SQL
statement. illegal syntax, or spaced the statement statement. Check the concatenation
over several lines without of multi-line SQL statements.
concatenating the parts of the
statement correctly.
321 — Insert or update The converted binary value exceeds Make sure the longbuffer setting is
35
Problem Reason Remedy
value too long. either the capacity of the not lower than the communications
communications API or the current API value.
longbuffer setting.
9279 — Cannot find Usually this message means that the Check that the comdll statements
specified protocol specified protocol cannot find the entry are correctly specified in the SQL.INI
entry. it is looking for in the [win32client.dll] file. Check that you have supplied all
section of the SQL.INI file. the needed keywords in the SQL.INI
file that apply to the SQLRouters you
are using.
30002 — Invalid The SAL functions used to invoke stored Make the calls in the correct
function call sequence procedures were called in an invalid sequence. (Read the Stored
sequence. procedures section of the chapter
for your database for more
information.)
30003 — Invalid An attempt was made to get the next The end of result sets can be
attempt to obtain a result set from a stored procedure even detected by checking the
subsequent result set. though there were no more result sets. bEndOfResult flag in the parameter
list for the SAL function that gets the
next result set. Error code 30003 is
returned if SqlExecute is called even
though bEndOfResult was TRUE.
Sample Applications
Several sample SQLWindows applications are installed in the SAMPLES subdirectory of the installation
directory for SQLWindows.
The sample applications listed in this section illustrate various aspects of coding a SQLWindows application
in conjunction with a particular router and database. The list of sample applications in this section are
organized by target database.
36
Oracle
The sample application ORADEMO.APP shows how to use the SAL function SqlPLSQLCommand to call an
Oracle stored procedure. For more information about this function, read the section Stored procedures on
page 5-12.
37
Chapter 3 – Connecting to Informix
This chapter describes how to connect SQLWindows/32 applications to Informix databases.
It is recommended that you read all of Chapter 1 – Overview and Chapter 2 – Initializing and Testing Your
Connection before you read this chapter.
You connect SQLWindows/32 applications to Informix databases using the native router, SQLRouter/Informix.
Chapter Contents
The following features of Informix can affect the way you write your SQLWindows/32 application or the way it
behaves when you connect to it with SQLRouter/Informix:
• “Arithmetic Functions” on page 38
• “Autocommit” on page 39
• “Cursor Context Preservation” on page 39
• “Cursors” on page 39
• “Data Types” on page 39
• “DDL Statement Support” on page 40
• “Empty Strings” on page 40
• “Isolation Levels” on page 41
• “Lock Time-Out” on page 41
• “Miscellaneous Features” on page 41
• “Positioned Updates” on page 41
• “SET Statement Support” on page 42
• “SQL.INI Keywords” on page 42
• “Stored Procedures” on page 45
• “Storing TEXT and BYTE Data” on page 47
Arithmetic Functions
You can use the following arithmetic functions in your SQLWindows/32 applications:
• ABS, ACOS, ASIN, ATAN, ATAN2, COS, EXP, LOGN, LOG10, MOD, POW, ROOT, SIN, SQRT, TAN
38
Autocommit
Informix databases support autocommit. Autocommit is off by default. Informix has three database modes:
default, ANSI, and Transaction. The default mode can be further configured into two submodes: log on and
log off. These modes (and submodes) are configured by the database administrator—you cannot configure
these from your application.
With the default mode in the log off submode, all the SQL statements you execute in your application are
committed automatically, regardless of whether you have turned autocommit on or off in your application.
With the default mode in the log o submode, or the ANSI or Transaction modes, if you turn autocommit on,
all the SQL statements you execute in your application are committed automatically; if you turn autocommit
off, your application must explicitly commit or roll back any SQL statements you have executed.
For more background information, see “Autocommit” on page 12.
Cursors
A SQLWindows/32 application that connects to Informix has no limit on the number of cursors it can create
and use. You can connect to more than one database and more than one database server in the same
application.
You cannot open a cursor WITH OPTIMIZATION or READ ONLY.
For related information, see “Handles, Contexts, and Connections” on page 17.
Data Types
The following table shows the mapping between the data types supported by a SQLWindows/32 application
and the data types supported by an Informix database server.
39
Informix Data Type
LONG STRING TEXT (255 or more bytes; online only) BYTE (255 or more bytes; online only)
CHAR (255 bytes to 32,767 bytes; online only) CHAR (255 bytes to 32,511 bytes;
SE only) VARCHAR (255 bytes; online only)
NUMBER SMALLINT (-215 to 215-1)
SERIAL (1 to 231-1)
INTEGER (-232 to 231-1) SMALLFLOAT
FLOAT
DOUBLE PRECISION REAL
DATE/TIME DATETIME YEAR TO DAY DATETIME HOUR TO FRACTION DATETIME YEAR TO
FRACTION
If you are using the SE database, you cannot CREATE or ALTER a table that has a VARCHAR column.
Empty Strings
On Informix, if you try to insert the empty string into a varying-length character string column (or try to
update such a column with the empty string), the database stores a space instead.
For background information, see “Nulls, Empty Strings, and Spaces” on page 21.
40
Isolation Levels
Informix supports the isolation levels shown in the following table:
RO Dirty Read
RL Committed Read
CS Cursor Stability
RR Repeatable Read
To set the isolation level in your application, call SqlSetIsolationLevel. For example, to set the isolation level to
Cursor Stability, put the statement in your SQLWindows/32 application:
Call SqlSetIsolationLevel(hSql,’CS’)
See the Function Reference for more information about this function.
For general information on isolation levels, see “Isolation Levels” on page 19.
Lock Time-Out
Informix supports lock time-outs. To specify “no wait”, specify a time-out value of zero. To specify “wait
forever, specify a time-out value of –1.
For general information on lock time-outs, see “Lock Time-Out” on page 21.
Miscellaneous Features
You can use the following Informix database features in your SQLWindows/ 32 applications:
• New data distribution features
• DBINFO utility function
• TRIM string function
Positioned Updates
A SQLWindows/32 application can do positioned updates against an Informix database.
For more information, see “Positioned Updates” on page 23.
41
SET Statement Support
You can use the following SET statements in your SQLWindows/32 application when connecting to an
Informix database:
• SET DATASKIP statement
• SET PDQPRIORITY statement
• SET TRANSACTION statement
SQL.INI Keywords
This section contains the keywords you need or might want to use in the SQL.INI file when connecting a
SQLWindows/32 application to an Informix Database.
For general information about SQL.INI, see “Initializing SQLWindows Applications” on page 28.
buffrow
Use this keyword to control the buffering of data between your SQLWindows application and
SQLRouter/Informix.
Section [infogtwy]
Default 0
Syntax buffrow=number_of_rows
Description This keyword controls the buffering of data between your SQLWindows/32 application
and SQLRouter/Informix. By decreasing the buffrow value, response time can be
improved significantly. In contrast, larger values increase data throughput, but lengthen
the response time.
The values for buffrow can range from 0 through 32767. Assigning a value does not
guarantee that the current INMESSAGE is of sufficient size to fulfill the request. In these
cases, the number of buffered rows may be considerably less.
The default value of zero causes SQLRouter/Informix to revert to buffering data based on
the number of rows which will fit within the current INMESSAGE buffer size.
Example This statement instructs SQLRouter/Informix to perform single row fetches into the
INMESSAGE buffer:
buffrow=1
Notes The buffrow keyword has no effect on the manner in which data is buffered and
transported across the network by Informix-Net.
You can also configure the buffering of data for individual SQL handles using the
SqlSetParameterAll function. Assuming nBuffrow has already been assigned the value
desired for SQL handle hSql, you can make the following call:
SqlSetParameterAll(hSql,DBP_BUFFROW,nBuffRow,FALSE,TRUE)
42
comdll
Identify the SQLRouters available between SQLWindows/32 (or a client application created with
SQLWindows) and the database.
Section [win32client.dll]
Syntax comdll=communication_dll_name
Description This keyword identifies the filename of a SQLRouter DLL. You can put more than one
comdll statement in the SQL.INI file. If you use InformixNet 5.x, the value of
communication_dll_name to use for SQLRouter/Informix is sqlirt32. If you use
InformixNet 7.x, the value to use is sqlifx32.
Notes For related information, read Connect search order on page 1-6
defconnect
Use this keyword to connect using information in the INFORMIX.INI file.
Section [infogtwy]
Default off
Syntax defconnect={on|off}
Description This keyword lets you connect to an informix database using the user name, password,
service, and hosted listed in the INFOMIX.INI file. You specify this information with the
Informix SETNET utility.
Example This statement instructs SQLRouter/Infomix to connect using the information in
INFORMIX.INI
defconnect=on
log
Use this keyword to define the database router activity log and enable logging.
Section [win32client.irt32] or [win32client.ifx32]
Syntax log=fully_qualified_path_name
Description Specify any valid file pathname after the keyword. If the file does not exist, it is created. If
the file already exists, it is overwritten (unless the /Fa option is specified see below).
Once the log statement has been added to the SQL.INI file, logging is performed
automatically.
You can specify one or more of the options listed below after the fully qualified
pathname to customize the output:
/Bx — exclude bind variable values (use [win32client.ifx32] if you are using comdll
SQLIFX32 or [win32client.irt32] if you are using SQLIRT32)
/Fa — append to existing file
/FD — display fetch data
/Ld — display LONG data read or written
/Tx — exclude timestamps
43
Enter the options exactly as shown, keeping upper-case letters in upper-case and lower-
case letters in lower case.
Example This example calls for a log file that does not include timestamps on entries (to conserve
disk space), and displays the input and output of all LONG data (including TEXT and
IMAGE data items).
[win32client.irt32] log=c:\gupta\informix.log /Tx /Ld
longbuffer
Use this keyword to specify the maximum number of bytes of long data type columns to retrieve or send.
Sections [infogtwy]
Default 32 Kbytes. Setting a value less than the default will cause the value to be reset to the
default.
Syntax longbuffer=number_of_bytes
Description This keyword sets the size of the buffer that holds LONG data. The maximum size is
limited only by operating system constraints. Normally, the optimal size that avoids data
loss is the largest column of LONG data to be sent or retrieved by the SQLWindows
application. A larger buffer uses more memory but reduces network traffic. A smaller
buffer uses less memory but increases network traffic. If the buffer is too small to hold all
of the data, the excess is truncated.
It is recommended that you not specify a value for longbuffer larger than the maximum
LONG column size in any of the tables stored in any of those databases.
Example This statement sets to 2K the maximum number of bytes of LONG column data to retrieve
from or send.
longbuffer=2000
Notes You can also set this variable in a SQLWindows/32 program by calling SqlSetParameterAll
with the DBP_LONGBUFFER parameter (defined in SQLNWKCN.APL). This allows you to
tailor the size of the buffer to the application.
remotedbname
Use this keyword to specify the name of the database your SQLWindows/32 application connects to, the
connect string it uses, and (optionally) the host where the database is located and the service through which
you access it.
Section [infogtwy]
Syntax remotedbname=db_name1,connect_string[, -hhostname [ -
sservicename]]
Description db_name specifies the database. The name may not be more than 8 characters long.
connect_string is the INFORMIX-SQL DATABASE statement. This statement is case
sentitive.
If you do not specify hostname and servicename, SQLRouter/Informix uses the values for these names
specified in the Informix initialization file INFORMIX.INI. (You can modify these names
with the Informix SETNET utility.) If you are using InformixNet 7.2, use the SETNET32
utility which modifies entries in the registries.
44
You can specify only one hostname and servicename in INFORMIX.INI. To connect to multiple servers
concurrently, you must specify additional hostnames and servicenames using the -h and -
s flags by including additional remotedbname statements in the SQL.INI file.
Examples: This example identifies a database that SQLWindows/32 applications know as STORES
and that the Informix database server menlo knows as STORES2. The database is located
on a host named jupitor using the service named turbo.
remotedbname=STORES, DATABASE”STORES2@menlo”, hjupitor –sturbo
This example is just like the preceding one, but the service name is not specified; the
value is taken from the INFORMIX.INI file.
remotedbname=STORES, DATABASE”STORES2@menlo”, -hjupitor
This example is like the preceding one, but the host and service names are both taken
from the INFORMIX.INI file.
remotedbname=STORES, DATABASE”STORES2@menlo”
This example identifies a database that SQLWindows/32 applications know as STORES.
The connect string specifies the database server name menlo and the path of the
database STORES2. The hostname and the service name are the defaults specified in the
INFORMIX.INI file.
remotedbname=STORES, DATABASE”//menlo/sd3/infse41/stores2”
yieldonservercall
Use this keyword to turn asynchronous processing in Informix I-Net on or off.
Sections [infogtwy]
Default off
Syntax yieldonservercall={on|off}
Description This statement instructs SQLRouter/Informix to share the CPU with other applications or
other modules of your application. By setting this keyword to “off” (the default), I-Net
lets other applications use the CPU while it waits for the server to complete the
operation it sent.
If your SQLWindows/32 application does asynchronous processing (for example, by
calling SalPostMsg to handle SQL statements) and you set yieldonservercall to off (or
took the default), you may get the message:
Error#111—SQL Application Programming Interface(API) recursively
entered.
To prevent this, set yieldonservercall to on.
Example This example allows Informix I-Net to do asynchronous processing.
yieldonservercall=on
Stored Procedures
Informix stored procedures are programs written in Informix Stored Procedure Language (SPL). Once you
create a procedure, it is stored in an executable format on the database server.
45
Procedures and triggers are database objects, just like tables; therefore, anyone with appropriate privileges
on a procedure may execute it.
If the stored procedure returns a result set, call SqlFetchNext to get rows from that result set.
46
More information on stored procedures
For general information about stored procedures, see “Stored Procedures” on page 26.
Actions
Call SqlConnect(hSql)
If not PrepareAndExecute(hSql,'CREATE TABLE longt(n FLOAT, s TEXT)')
...
If not SqlPrepare(hSql,'INSERT INTO longt
Unicode
VALUES(:nNumber,:sLong)')
...
If not SqlSetLongBindDatatype(2, BINDTEXT)
...
If not SqlExecute(hSql)
...
You must first prepare the INSERT or UPDATE statement, and then call SqlSetLongBindDatatype before you
execute the statement. The binding from the function SqlSetLongBindDatatype lasts only until your
application prepares the next SQL statement.
47
For more information on SqlSetLongBindDatatype, refer to the SQLWindows/32 Function Reference and the
online help.
Unicode support has been certified for Informix 11.5 using Team Developer 5.2 SP1 and above.
To use this unicode support, the following must be in place:
• Database created must be a UTF8 database.
• Informix server locale environment variables must be UTF8. For example:
CLIENT_LOCALE=EN_US.utf8
DB_LOCALE=EN_US.utf8
SERVER_LOCALE=EN_US.utf8
DBLANG_EN-US.utf8
Use the informix setnet32 utility to set these environment variables.
• Your Informix client machine should match these settings.
• You need to add the sql.ini entry “unicodedb=on” to your informix section of your sql.ini; for example:
[infogtwy]
remotedbname=testdb,DATABASE"testdb",-h192.168.146.119 - s1528 -vqadbs3
longbuffer=102400 buffrow=0 defconnect=off yieldonservercall=off unicodedb=on
48
Chapter 4 – Connecting to Microsoft SQL
Server
This chapter describes how to connect SQLWindows applications to Microsoft SQL Server version 6.5 and
above.
It is recommended that you read all of Chapter 1 – Overview and Chapter 2 – Initializing and Testing Your
Connection before you read this chapter.
You connect SQLWindows applications to ODBC data sources with the SQLWindows ODBC router,
SQLRouter/ODBC. This router conforms to the ODBC specification up to core levels 1 and 2 (ODBC 2.0 level
within the 3.0 specification). See Chapter 8 – Connecting to Multiple Databases Concurrently for more on the
ODBC driver.
Autocommit
When you connect to Microsoft SQL Server 6.5 and 7.0, autocommit is on by default.
Data Definition Language (DDL) statements, such as CREATE TABLE, are always committed immediately, even
if autocommit is off.
If autocommit is off, and you either disconnect from the database or exit the application (whether normally
or abnormally) before committing or rolling back a pending transaction, the ODBC driver sends a ROLLBACK
request to the database server.
For background information on autocommit, see “Autocommit” on page 12.
For information on autocommit and cursor context preservation, see the next section, “Cursor Context
Preservation”.
49
• decimal—The server can be configured to provide a maximum precision of 38 decimal digits (the default
maximum is 28 decimal digits). However, 22 decimal digits is the maximum precision that SQLWindows
supports for this data type.
• numeric—The server can be configured to provide a maximum precision of 38 decimal digits (the default
maximum is 28 decimal digits). However, 22 decimal digits is the maximum precision that SQLWindows
supports for this data type
• double precision—Both the server and SQLWindows support a maximum precision of 17 decimal digits
for this data type.
The decimal and numeric data types, which are identical, allow the exact representation of a fractional value.
This is unlike double precision or float (to which double precision is mapped), which typically allow only
approximate values.
The following table shows the data type mappings between SQLWindows and Microsoft SQL Server using an
ODBC connection:
50
image
binary
varbinary
text/ntext
varchar/nvarchar >= 255
char/nchar >= 255
• Beginning with Team Developer 5.2, you can use the binary variable when dealing with SQLServer’s binary
datatypes: image, binary, and varbinary. Unlike the method using Team Developer’s Long String, the binary
variable does not require you to call SqlSetLongBindDatatype.
Empty Strings
On Microsoft SQL Server 6.5 and 7.0, if you try to insert the empty string into a varying-length character string
column (or try to update such a column with the empty string), the database stores a space instead.
For background information, see “Nulls, Empty Strings, and Spaces” on page 21.
Isolation Levels
Microsoft SQL Server defines four isolation levels in terms of dirty reads, nonrepeatable reads and phantom
rows. (See Isolation Levels on page for the definitions of these terms.)
• SQL_TXN_READ_UNCOMMITTED — Dirty reads, nonrepeatable reads, and phantom rows are all possible.
• SQL_TXN_READ_COMMITTED — Dirty reads are prevented. Nonrepeatable reads and phantom rows are
possible.
• SQL_TXN_REPEATABLE_READ — Dirty reads and nonrepeatable reads are prevented. Phantom rows are
possible.
• SQL_TXN_SERIALIZABLE — Dirty reads, nonrepeatable reads, and phantom rows are all prevented
(transactions are serializable).
SQLWindows supports the RO, RL, CS, and RR isolation levels. When a SQLWindows application connects to
Microsoft SQL Server, these isolation levels are mapped to the SQL Server isolation levels as follows:
RO SQL_TXN_READ_UNCOMMITTED
RL SQL_TXN_READ_COMMITTED
51
CS SQL_TXN_REPEATABLE_READ
RR SQL_TXN_SERIALIZABLE
Lock Time-Out
The default value for lock time-out with Microsoft SQL Server is zero. This means there is no lock time-out.
For more background information, see “Lock Time-Out” on page 21.
Native Connectivity
Microsoft SQL Server 6.5 and 7.0 uses ODBC as its native call-level interface. Microsoft SQL Server
automatically maps SAL statements to the appropriate ODBC functions. No ODBC calls appear in your
SQLWindows applications.
The level of SQL syntax and semantics supported is Core. The ODBC API conformance is Level II.
Positioned Updates
SQLWindows applications can perform positioned updates (WHERE CURRENT OF cursor updates) when
connected to Microsoft SQL Server. To learn how to code a positioned update, see “Positioned Updates” on
page 23.
Important: You cannot do positioned updates on a result set returned by a stored procedure. You should
always disable result set mode before calling a stored procedure.
For additional information on stored procedures, see “Stored Procedures” on page 57. For background
information on result set mode, see “Result Set Mode” on page 24.
52
Result Set Mode
Microsoft SQL Server provides backend support for scrollable cursors (result set cursors that scroll both
backwards and forwards). Consequently, you cannot create front end result sets (FERS) if you turn on result
set mode.
You must turn on result set mode to have more than one result set open at the same time. If result set mode
is off, you must fetch all of the rows from one result set before you can SELECT another result set. If you try to
SELECT a result set before fetching all the rows of a previously retrieved result set, you get the error:
[Microsoft][ODBC SQL Server Driver]Connection is busy with result for another
hstmt.
By default, result set mode is off for better performance. Also, you must always turn off result set mode
before calling a stored procedure, even when connecting via ODBC or OLE DB.
For background information on result set mode and scrollable cursors, see “Result Set Mode” on page 24. For
more information on FERS, see “Front End Result Sets” on page 16.
SET Statement
Microsoft SQL Server supports the SET statement. You use this statement to set various query-processing
options for the duration of your work session (that is, until you disconnect), or for the duration of a stored
procedure.
When you execute the SET statement from a SQLWindows application, you do so by specifying a specific SQL
handle. Nonetheless, the option you set applies to all statements executed on your current connection to the
database, regardless of the SQL handle you specify when you execute those statements.
For example, you can use SET to limit the number of rows returned in a result set, such as:
SqlPrepareAndExecute(hSql1,’SET ROWCOUNT 10’)
If you then retrieve a result set, the database returns no more than 10 rows, even if you specify a handle
other than hSql1 when you execute the SELECT statement, for example:
SqlPrepareAndExecute(hSql2,’SELECT * FROM MYTABLE’)
Read the Microsoft SQL Server online documentation for further information about the SET statement.
SqlDirectoryByName Semantics
When a SQLWindows application has connected to Microsoft SQL Server, calling the function
SqlDirectoryByName returns all of the databases listed in the ODBC.INI file. This list is not necessarily the
same as the list of all databases accessible to Microsoft SQL Server.
SQL.INI Keywords
This section contains the keywords you need or might want to use in the SQL.INI file when connecting a
SQLWindows application to Microsoft SQL Server.
53
buffrow
Use this keyword to control the buffering of data between your SQLWindows application and Microsoft SQL
Server.
Section [odbcrtr]
Default 0
Syntax buffrow=number_of_rows
Description This keyword controls the buffering of data between your SQLWindows application and
Microsoft SQL Server. By decreasing the buffrowvalue, response time can be improved
significantly. In contrast, larger values increase data throughput, but lengthen the
response time.
The values for buffrow can range from 0 through 32767. Assigning a value does not
guarantee that the current INMESSAGE is of sufficient size to fulfill the request. In these
cases, the number of buffered rows may be considerably less.
The default value of zero causes Microsoft SQL Server to revert to buffering data based on
the number of rows which will fit within the current INMESSAGE buffer size.
Example This statement instructs Microsoft SQL Server to perform single row fetches into the
INMESSAGE buffer:
buffrow=1
Notes The buffrowkeyword has no effect on the manner in which data is buffered and
transported across the network.
You can also configure the buffering of data for individual SQL handles using the
SqlSetParameterAll function. Assuming nBuffrowhas already been assigned the value
desired for SQL handle hSql, you can make the following call:
SqlSetParameterAll(hSql,DBP_BUFFROW,nBuffRow,FALSE,TRUE)
comdll
Identify the SQLRouters available between SQLWindows (or a client application created with SQLWindows)
and the database.
Section [win32client.dll]
Syntax comdll=communication_dll_name
Description This keyword identifies the filename of a SQLRouter DLL. You can put more than one
comdll statement in the SQL.INI file. The value of communication_dll_name to use for
SQLRouter/ODBC is sqlodb32.
Example comdll=sqlodb32
Notes For related information, see “Connect Search Order” on page 14.
log
Define the database router activity log and enable logging.
Section [win32client.odb32]
54
Syntax log=fully_qualified_path_name
Description Specify any valid file pathname after the keyword. If the file does not exist, it is created. If
the file already exists, it is overwritten (unless the /Fa option is specified see below).
Once the log statement has been added to the SQL.INI file, logging is performed
automatically.
You can specify one or more of the options listed below after the fully qualified
pathname to customize the output:
/Bx — exclude bind variable values
/Fa — append to existing file
/FD — display fetch data
/Ld — display LONG data read or written
/Tx — exclude timestamps
Enter the options exactly as shown, keeping upper-case letters in upper case and lower-
case letters in lower case.
Example This example calls for a log file that does not include timestamps on entries (to conserve
disk space), and displays the input and output of all LONG data (including TEXT and
IMAGE data items).
[win32client.odb32] log=c:\gupta\mssqlsrv.log /Tx /Ld
longbuffer
Specify the maximum number of bytes of LONG column data to retrieve or send.
Sections [odbcrtr]
Default 32 Kbytes. Setting a value less than the default will cause the value to be reset to the
default.
Syntax longbuffer=number_of_bytes
Description This keyword sets the size of the buffer that holds LONG data. The maximum size is
limited only by operating system constraints. Normally, the optimal size that avoids data
loss is the largest column of LONG data to be sent or retrieved by the SQLWindows
application. A larger buffer uses more memory but reduces network traffic; a smaller
buffer uses less memory but increases network traffic. If the buffer is too small to hold all
of the data, the excess is truncated.
If specified, the longbuffer statement applies to all databases connected to using ODBC. It
is recommended that you not specify a value for longbuffer larger than the maximum
LONG column size in any of the tables stored in any of those databases.
Example This statement sets to 64K the maximum number of bytes of LONG column data to
retrieve from or send to any database connected to using ODBC.
longbuffer=65536
Notes You can also set this variable in a SQLWindows program by calling SqlSetParameterAll
with the DBP_LONGBUFFER parameter (defined in SQLNWKCN.APL). This allows you to
tailor the size of the buffer to the application.
55
odbctrace
Trace all calls to the ODBC API.
Section [odbcrtr]
Default off
Syntax odbctrace={on|off}
Description The Microsoft ODBC Driver Manager can trace all calls made to the ODBC API. The trace
information is saved in the log file whose pathname is given in the odbtracefile
statement.
Example This statement enables ODBC API call tracing:
odbctrace=on
odbctracefile
Specify the pathname of the trace file for ODBC API calls.
Section [odbcrtr]
Default root_directory\sql.log
Syntax odbctracefile=fully_qualified_filename
Description This keyword specifies the pathname of the trace file for ODBC API calls. This keyword
has no effect unless the odbtrace keyword is set to “on”(see “odbctrace” on page 56).
Example This statement specifies that the trace file is called odbc.log, and that it is located in the
\logs directory on the client’s c: drive:
odbctracefile=c:\logs\odbc.log
remotedbname
Use this keyword to specify database names and their associated connect strings.
Section [odbcrtr]
Syntax remotedbname=db_name1,connect_string
Description db_name1 specifies the database name as it is known by the SQLWindows application;
the name may not be more than 8 characters long.
connect_string is the exact connect string you will use to connect to the ODBC data
source. Typically, this entry begins with the string "DSN=" to specify the data source
name specified in the ODBC Administrator tool.
The value specified in connect_string can include embedded spaces. Do not put
comments on the same line with the "remotedbname" statement. Everything from the
comma following db_name to the end of line is interpreted as the connect string.
Examples: Assume you have defined two data sources in ODBC Administrator. One is for Microsoft
SqlServer 7.0 (with a data source name of "MS SqlServer 7.0"), and the other is for a
Visual FoxPro database (with a data source name of "Visual FoxPro DB"). The
remotedbname statements look like:
remotedbname=SS70,DSN=MS SqlServer 7.0 remotedbname=VFP,
DSN=Visual FoxPro DB
56
Your Team Developer application sets the variable "SqlDatabase" to either "SS70" (to
connect to the SqlServer data source) or to "VFP" (to connect to the FoxPro database),
set SqlUser and SqlPassword appropriately, and issue the SqlConnect() call.
SqlRouter/ODBC obtains all the necessary information from the configuration maintained
by the ODBC Administrator utility.
Notes: The remotedbname parameter is not necessary for applications built using Team
Developer. It is required if you want to use the SqlTalk utility to connect to the ODBC data
source.
When connecting to any ODBC data source where the data source name was configured
by the ODBC Administrator tool, your application can bypass the remotedbname
parameter altogether, and set the variable SqlDatabase to the actual ODBC data source
name. Using the above example, if you issue the following statements (assume SqlUser
and SqlPassword are set), your program will connect correctly to the Microsoft SqlServer
7.0 data source without using the remotedbname parameter in SQL.INI:
Set SqlDatabase = "MS SqlServer 7.0"
Call SqlConnect (hSql)
Stored Procedures
Procedures containing SQL statements and procedure logic can be compiled and stored on SQL Server. These
procedures can return more than one result set, and can accept input bind variables (host variables) as
arguments (see “Stored Procedures” on page 26).
57
Executing Stored Procedures
Two new pairs of SAL functions have been introduced to support calling stored procedures.
The first pair is:
• OdrExecuteProc—Execute the specified stored procedure.
• OdrGetNextResults —Get the next result set (if any) from the stored procedure that was invoked with
OdrExecuteProc.
The second pair is:
• OdrPrepareProc—Prepare (compile) the invocation of the specified stored procedure.
• OdrPrepareNextResults—Prepare the (implied) statement that gets the next result set (if any).
You must turn off result set mode before calling a stored procedure.
Either SqlExecute or a function that implies execution of a prepared statement, such as SalTblPopulate, must
be called after calling OdrPrepareProc or OdrPrepareNextResults.
Once the result set has been retrieved, position the cursor to the first and subsequent rows in the result set
by calling the SqlFetchNext function. (For more information about this function, see the SQLWindows
Function Reference.)
Example Code
The code fragment below creates the stored procedure GetNames and stores it on the server. The procedure
returns all the values in the name column and the number column from the rooms table, and then all the
values in the name column from the guests table. The code invokes the stored procedure using the shorthand
ODBC procedure syntax. See the Microsoft ODBC 2.0 Programmer’s Reference and SDK Guide for more
information on the standard and shorthand syntax for calling stored procedures.
The current column values being fetched are stored in the INTO variables :strName and :nNumber from the
first result set, and the INTO variable :strName from the second result set.
Call SqlSetResultSet(hSql, FALSE)
Set strProcedure=’CREATE PROCEDURE GetNames AS ’ ||
’SELECT name,number FROM rooms ’ ||
’SELECT name FROM guests’
Call SqlPrepareAndExecute(hSql, strProcedure)
If OdrExecuteProc(hSql,’{call GetNames()}’,’:strName,:nNumber’) Loop
If SqlFetchNext(hSql, nRet)
...
Else If (nRet=FETCH_EOF)
If NOT OdrGetNextResults(hSql,’:strName’,
bEndOfResults)
If bEndOfResults
Break
In the above code fragment, the functions OdrExecuteProc and OdrGetNextResults were called.
Alternatively, you can prepare the invocation of the stored procedure as a separate step by replacing
OdrExecuteProc with:
If OdrPrepareProc(hSql,’{call GetNames()}’,’:strName’)
If SqlExecute(hSql)...
And you can replace the call to OdrGetNextResults with:
If NOT OdrPrepareNextResults(hSql,’:strName,:nNumber’,
58
bEndofResults)
If NOT bEndOfResults
If SqlExecute(hSql)...
SAL Extensions
This section describes the Scalable Application Language (SAL) extensions that allow you to work with stored
procedures on Microsoft SQL Server version 6.5 and 7.0.
For more information about stored procedures and ODBC, see the Microsoft ODBC 2.0 Programmer’s
Reference and SDK Guide. For more information about stored procedures and Microsoft SQL Server, see the
SQL Server online documentation (click the SQL Server Books Online icon in the SQL Server Tools program
group).
OdrExecuteProc
Syntax bOk=OdrExecuteProc(hSql,strProc,strIntoList)
Sql Handle: hSql
String: strProc
String: strIntoList
Parameters hSql—A handle that identifies a connection context to the database.
strProc—The text of the call to the stored procedure to be executed.
strIntoList—The list of INTO variables into which the stored procedure’s result set values
(if any) are returned.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Description This function executes a stored procedure on Microsoft SQL Server.
Separate the variables listed in strIntoList with commas and precede each variable name
with a colon. If the stored procedure returns zero rows, the variables in strIntoList keep
whatever values they had before the call to OdrPrepareNextResults. If you know the
59
stored procedure does not execute a SELECT statement, use strNull as the value for
strIntoList.
If a result set is returned, its associated cursor points to just before the first row of the
result set. To set the INTO variables in strIntoList to the column values of the first row, call
SqlFetchNext. To obtain subsequent rows in the result set, continue to call SqlFetchNext.
Once all the rows in a given result set have been retrieved, get the next result set (if any)
by calling OrdGetNextResults.
Limitations The function OdrExecuteProc does not accept bind variables. (Compare OdrPrepareProc
on page 61, which does accept bind variables.)
Notes See “OdrGetNextResults” on page 60.
Examples This example executes the stored procedure mysp. This procedure accepts no arguments,
and it returns a result set consisting of a single column. The call to the stored procedure
is specified using the shorthand ODBC syntax. The data type of the INTO variable :strOut
is assumed to match the column data type returned by the stored procedure.
Call OdrExecuteProc(hSql,’{call mysp()}’,’:strOut’)
See also the sample application ODBSAL1.APP in the SAMPLES subdirectory of the
SQLWindows installation directory.
OdrGetNextResults
Syntax bOk=OdrGetNextResults(hSql, strIntoList, bEndOfResults)
Sql Handle: hSql
String: strIntoList
Boolean: bEndOfResults
Parameters hSql—A handle that identifies a connection context to the database.
strIntoList—The list of INTO variables into which the stored procedure’s result set values
(if any) are returned.
bEndofResults—Boolean variable that indicates if there were no more result sets to be
retrieved.
Return Value bOK is set to TRUE if the function succeeds and to FALSE if it fails.
Description If the stored procedure invoked by calling OdrExecuteProc returns more than one result
set, use OdrGetNextResults to get the second and subsequent result sets.
Separate the variables listed in strIntoList with commas and precede each variable name
with a colon. If the stored procedure returns zero rows, the variables in strIntoList keep
whatever values they had before the call to OdrPrepareNextResults.
If a result set is returned, its associated cursor points to just before the first row of the
result set. To set the INTO variables in strIntoList to the column values of the first row, call
SqlFetchNext. To obtain subsequent rows in the result set, repeatedly call SqlFetchNext.
Once all the rows in a given result set have been retrieved, get the next result set (if any)
by again calling OrdGetNextResults.
If OdrGetNextResults is called and there are no more result sets, bOk is set to FALSE and
bEndOfResults is set to TRUE.
60
Notes See “OdrExecuteProc” on page 59.
Examples This example gets the next result set (if any) returned by the stored procedure invoked
with OdrExecuteProc. The parameter hSql denotes the same handle that was used in the
call to OdrExecuteProc.
Call OdrGetNextResults(hSql,’:strOut’, bEndOfResults)
See also the sample application ODBSAL1.APP in the SAMPLES subdirectory of the
SQLWindows installation directory.
OdrGetReturnStatus
Syntax bOk=OdrGetReturnStatus(hSql, Number_Variable_Name)
Parameters hSql — A handle that identifies a connection context to the database.
Return Value nReturn is the return value of the stored procedure.
Description This function gets the return value of a stored procedure You should compile the stored
procedure using OrdPrepareProc only. If you use OrdExecuteProc, then this function will
fail. If you use OrdExecuteProc, the number variable will be set to 0. It will not contain
the actual return status information.
Notes The calling status for the stored procedures is slightly different if you use
OrdGetReturnStatus. You have to use the complete ODBC syntax for stored procedures.
You have to specify the bind variable name which is expected to contain the return status
information in the call to OrdPrepareProc. See the code example below.
This function should be called only after all the result sets from this stored procedure
have been retrieved.
Examples The syntax used in OrdPrepareProc is different now. You have to specify a bind variable
name before Call in order to use OrdGetReturnStatus. If you call OrdGetReturnStatus
without specifying a variable name in OrdPrepareProc, no error is returned. But the
return variable will contain 0.
Call SqlConnect(hSql)
Call OrdPrepareProc(hSql,’ {:nReturn=call MySP (:param1,
:param2)}’,’:bind1’) Call SqlExecute(hSql)
While SqlFetchNext(hSql, nFetchInd)
<process fetched data>
Call OrdGetReturnStatus(hSql, nReturn)
OdrPrepareProc
Syntax bOk=OdrPrepareProc(hSql, strProc, strIntoList)
Sql Handle: hSql
String: strProc
String: strIntoList
Parameters hSql—A handle that identifies a connection to the database.
strProc—The text of the call to the stored procedure to be prepared.
61
strIntoList—The list of INTO variables into which the stored procedure’s result set values
(if any) are returned.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Description This function prepares (compiles) the invocation of a stored procedure for subsequent
execution on Microsoft SQL Server. The prepared invocation of the stored procedure
must then be executed explicitly (by calling the SqlExecute function) or implicitly (by
calling, for example, the SalTblPopulate function).
Separate the variables listed in strIntoList with commas and precede each variable name
with a colon. If the stored procedure returns zero rows, the variables in strIntoList keep
whatever values they had before the call to OdrPrepareNextResults. If you know the
stored procedure does not execute a SELECT statement, use strNull as the value for
strIntoList.
Limitations Input bind variables in the argument list of the call to a stored procedure must be listed
explicitly using the variable name preceded by a colon. You cannot use parameter
markers (the question mark (?) syntax) as defined in ODBC. Also, input bind variables
cannot be of type LONG STRING.
Microsoft SQL Server allows a stored procedure to be defined to pass values back to the
calling program through output bind values, a function result, or both. If the stored
procedure has output parameters, strProc must include output bind variables in the
argument list to match those parameters. However, the values assigned to those output
parameters on the server do not get assigned to the output bind variables in your
SQLWindows application; the application never “sees” those values. After the call to the
stored procedure returns, the values of the output bind variables are undefined (see
“Retrieving Output Parameters from Stored Procedures” on page 64).
Likewise, a function result returned by the stored procedure never gets back to the
SQLWindows application. Consequently, you cannot assign the function result from a
stored procedure to a variable or use it in an expression.
Notes See “OdrPrepareNextResults” on page 62.
Examples This example prepares the stored procedure myproc. This procedure is assumed to
accept two input parameters—the bind variables :v1 and :v2 need to have been declared
of the appropriate type—and to return an initial result set consisting of a single column.
The call to the stored procedure is specified using the shorthand ODBC syntax. The data
type of the INTO variable :strOut is assumed to match the column data type of the first
result set returned by the stored procedure.
Call OdrPrepareProc(hSql,’{call myproc(:v1,:v2)}’,’:strOut’)
See also the sample application ODBSAL2.APP in the SAMPLES subdirectory of the
SQLWindows installation directory.
OdrPrepareNextResults
Syntax bOk=OdrPrepareNextResults (hSql, strIntoList, bEndOfResults)
Sql Handle: hSql
String: strIntoList
Boolean: bEndOfResults
62
Parameters hSql — A handle that identifies a connection to the database.
strIntoList—The list of INTO variables into which the stored procedure’s result set values
(if any) are returned.
bEndofResults — Boolean variable that indicates if there were no more result sets to be
retrieved.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Description If the stored procedure specified in the call to OdrPrepareProc returns more than one
result set, use OdrPrepareNextResults followed by explicit execution (calling the
SqlExecute function) or implicit execution (calling, for example, the SalTblPopulate
function) to get the next result set.
Separate the variables listed in strIntoList with commas and precede each variable name
with a colon. If the stored procedure returns zero rows, the variables in strIntoList keep
whatever values they had before the call to OdrPrepareNextResults.
If a result set is returned, its associated cursor points to just before the first row of the
result set. To set the INTO variables in strIntoList to the column values of the first row, call
SqlFetchNext. To obtain subsequent rows in the result set, continue to call SqlFetchNext.
Alternatively, you can call SalTblPopulate to fetch the rows of data in the result set.
Once all the rows in a given result set have been retrieved, get the next result set (if the
stored procedure has another SELECT statement it can execute) by again calling
OrdPrepareNextResults.
If OdrPrepareNextResults is called and there are no more result sets, bOk is set to FALSE
and bEndOfResults is set to TRUE.
See Also OdrPrepareProc on page 61
Example This example gets the next result set (if any) returned by the stored procedure specified
in OdrPrepareProc. The parameter hSql denotes the same handle that was used in the
call to OdrPrepareProc.
Call OdrPrepareNextResult(hSql,’:strOut’, bEndOfResults)
See also the sample application ODBSAL2.APP in the SAMPLES subdirectory of the
SQLWindows installation directory.
No scrollable cursors
The cursor associated with a result set returned by a stored procedure can scroll forward only.
No positioned updates
You cannot do positioned updates on a result set returned by a stored procedure.
63
No output values
When calling a stored procedure that has output parameters in its parameter list, you must include an output
bind variable (of the appropriate type) in the argument list of the call for each such parameter. However, the
values returned by the stored procedure on the server do not get assigned to those output bind variables on
the client, so your SQLWindows application cannot access those values. After the call to a stored procedure
returns, the values of any output bind variables are undefined.
Similarly, if the stored procedure returns a function result, that value cannot be accessed by your
SQLWindows application. Consequently, the return value cannot be assigned to a variable in your
SQLWindows application, or used in an expression.
64
‘@test = :nTest ‘ ||
‘@result = @outparm output ‘ ||
‘SELECT @outparm‘
Set nTest = 2
Call OdrPrepareProc(hSql,strSqlExecute, ‘:dfAu_lname‘)
Call SqlExecute (hSql)
While NOT nFetchInd
Call SqlFetchNext(hSql,nFetchInd)
Call OdrPrepareNextResults (hSql, ‘:dfFoo‘, bMoreResults)
Call SqlExecute (hSql)
Set nFetchInd = FALSE
While NOT nFetchInd
Call SqlFetchNext(hSql,nFetchInd)
Call OdrPrepareNextResults(hSql, ‘:dfOutParm‘, bMoreResults)
Call SqlExecute (hSql)
Set nFetchInd = FALSE
While NOT nFetchInd
Call SqlFetchNext(hSql,nFetchInd)
65
Chapter 5 – Connecting to Oracle
This chapter describes how to connect SQLWindows applications to Oracle databases using the Team
Developer native router, SQLRouter/Oracle. It describes (in alphabetical order) various features of Oracle that
can affect the way you write your SQLWindows application or the way it behaves when you connect to it with
SQLRouter/Oracle.
It is recommended that you read all of Chapter 1 – Overview and Chapter 2 – Initializing and Testing Your
Connection before you read this chapter.
You connect SQLWindows applications to Oracle databases using either the native router, SQLRouter/Oracle,
or the ODBC router, SQLRouter/ODBC. To learn about connecting with the native router, read this chapter. To
learn about connecting with the ODBC router, read Chapter 7 – Connecting to Databases Using ODBC.
Autocommit
Oracle database servers support autocommit. Autocommit is off by default.
If you turn on autocommit, both DML (Data Manipulation Language) statements (such as UPDATE, INSERT,
and DELETE) and DDL (Data Definition Language) statements (such as CREATE TABLE and DROP TABLE) are
committed immediately.
Note: With an Oracle database, DDL statements are always committed immediately, even if autocommit is off.
If you turn on autocommit, you cannot prepare a SQL statement, then execute it multiple times. Once you
execute the statement, the prepare context is lost and you must prepare it again. If you turn off autocommit
and turn on cursor context preservation, however, you can re-execute a prepared state multiple times
(possibly with new values for any bind variables in the prepared statement). For more information, see
“Cursor Context Preservation” which follows.
For background information about autocommit, see “Autocommit” on page 12.
66
Data Types
The table that follows shows the mapping between the data types supported by a SQLWindows application
and the data types supported by an Oracle database server.
The value of maxvarch in the table above is either 4,000 or 32,000. If you have a LONG STRING bind variable
in an SQL statement, and that bind variable is associated with a VARCHAR or VARCHAR2 column, you can
store at most 4,000 bytes in that variable. If you use a PL/SQL program variable that is associated with a
VARCHAR or VARCHAR2 column, you can store at most 32,000 bytes in that variable.
The MLSLABEL data type applies only to Trusted Oracle database servers.
DBA Authority
The Gupta router for Oracle allows you to indicate that you wish to connect to a database in the “sysdba”
role. You do this from Connectivity Administrator by adding “as sysdba” to the Oracle connection string , as
shown in this example line from SQL.INI:
remotedbname=ora9i,@ora9i as sysdba
Thereafter, you can set the user ID as “sys” during a login and the router will actually connect with “sys as
sysdba”.
If you are connecting to Oracle using an OLE DB data source, the additional phrase in the connect string is not
required; “sys” will connect with sysdba privileges.
OS Authentication
You can connect to Oracle from Team Developer using OS authentication with username “dummy.” The
password is essentially ignored in this case.
Sample code:
67
On SAM_AppStartup
Set SqlUser='dummy'
Set SqlPassword='' ! could be anything
Set SqDatabase='Oracle11gDB' ! database name in sql.ini file.
Call SqlConnect(hSql)
This will connect to the Oracle database using the Operating System login (OS authentication).
Dynamic PL/SQL
SQLWindows applications use dynamic SQL statements to perform operations on the databases you connect
to. These statements (such as SELECT, INSERT, UPDATE, CREATE TABLE, and so on) are compiled and executed
“on the fly” (while the SQLWindows application is running).
Oracle supports a different (though similar) feature called dynamic PL/SQL. This feature lets you assign a
block of PL/SQL statements to a string variable, then have the database compile and execute that block of
statements at runtime.
You cannot execute dynamic PL/SQL blocks in your SQLWindows applications. However, you can achieve a
similar effect in your application as follows: Create a stored procedure that contains the PL/SQL statements
you want to execute, invoke that stored procedure, and then drop the procedure before you exit the
application (so the procedure does not continue to be stored in the database).
Empty Strings
On Oracle, if you try to insert the empty string into a varying-length character string column (or try to update
such a column with the empty string), the database stores NULL instead.
For background information, see “Nulls, Empty Strings, and Spaces” on page 21.
Isolation Levels
Oracle does not support setting isolation levels if an application uses dynamic (rather than static) SQL.
Because all SQLWindows applications use dynamic SQL statements, you cannot call SqlSetIsolationLevel in
your SQLWindows application when connected to Oracle.
You cannot set isolation levels when connected to an Oracle database. However, you can affect data
consistency and concurrent access to data by doing either of the following:
• Lock the entire table with the LOCK TABLE statement.
• Lock certain rows with the SELECT...FOR UPDATE statement.
Locking an entire table is very heavy-handed and risky. No one other than the user who has locked the table
can do any operations on the table until it is unlocked. Even if the application locks the table for only a short
period of time, the penalty paid by other users is usually unacceptably high.
Locking only certain rows during a transaction is much more selective and allows other users to access all
data in the database except for the locked rows. However, if the user who has the lock takes a long time to
complete the transaction, all other users who need to access that data are forced to wait.
68
For some background on isolation levels, see “Isolation Levels” on page 19.
Lock Time-Out
Oracle servers do not support lock time-out. However, you can enable autocommit (see “Autocommit” on
page 5-2), which has the side effect of eliminating deadlocks.
For some background on lock time-outs, see “Lock Time-Out” on page 21.
Positioned Updates
SQLWindows applications can perform positioned updates against an Oracle database.
For more information, see “Positioned Updates” on page 23.
SQL.INI Keywords
This section describes the keywords you should use in the SQL.INI file when connecting a SQLWindows
application to an Oracle database.
For more information about the SQL.INI file, see “Initializing SQLWindows Applications” on page 28.
69
comdll
This keyword identifies the SQLRouters available between SQLWindows (or a client application created with
SQLWindows) and the database.
Section [win32client.dll]
Syntax comdll=communication_dll_name
Description This keyword identifies the filename of a SQLRouter DLL. You can put more than one
comdllstatement in the SQL.INI file. The value of communication_dll_nameto use for
SQLRouter/Oracle is sqlora32.
Example comdll=sqlora32
Notes For related information, see “Connect Search Order” on page 14.
fetchrow
This keyword specifies the maximum number of rows SQLRouter/Oracle retrieves per each network
message during cursor operations (fetching) on a result set.
Section [oragtwy]
Default 64
Syntax fetchrow=number_of_rows
Description number_of_rows must be a positive integer (but do not put a plus sign).
The fetchrow value specifies the number of rows that the OCI (i.e. Oracle Call Interface)
layer "prefetches" and makes available to your application. If the value is not set or the
value is less than 64, a default value of 64 is used.
You can improve performance by assigning a suitable value to fetchrow.
To achieve good performance, you must balance the number of rows per fetch (which
increases the memory used) against the operating system's need for memory (which
causes the OS to swap memory when not enough is available).
In general, on a slow network connection such as a WAN, higher values for fetchrow (up
to the actual number of rows in a given query) give the best results.
Your SQLWindows application still receives a single row for each call to SqlFetchNext,
regardless of the value assigned to fetchrow.
Example This example indicates that you want to retrieve only 100 rows with each fetch.
fetchrow=100
The following example indicates that you want to fetch only a single row (in effect,
disabling the feature).
fetchrow=1
log
This keyword defines the database router activity log and enable logging.
Section [win32client.ora32]
Syntax log=fully_qualified_path_name
70
Description Specify any valid file pathname after the keyword. If the file does not exist, it is created. If
the file already exists, it is overwritten (unless the /Fa option is specified see below).
Once the log statement has been added to the SQL.INI file, logging is performed
automatically.
You can specify one or more of the options listed below after the fully qualified
pathname to customize the output:
/Bx—exclude bind variable values
/Fa—append to existing file
/FD—display fetch data
/Ld—display LONG data read or written
/Tx—exclude timestamps
Enter the options exactly as shown, keeping upper-case letters in upper case and lower-
case letters in lower case.
Example This example calls for a log file that does not include timestamps on entries (to conserve
disk space), and displays the input and output of all LONG data (including TEXT and
IMAGE data items).
[win32client.ora32]
log=c:\gupta\oracle.log /Tx /Ld
longbuffer
This keyword specifies the maximum number of bytes of long data type columns to retrieve or send, and
truncates excess bytes.
Sections [oragtwy]
Default 32,768. Setting a value less than the default will cause the value to be reset to the
default.
Syntax longbuffer=number_of_bytes
Description The maximum size of this keyword is limited only by operating system constraints.
Reduce the value of this keyword to conserve memory or reduce network traffic. If you
use longbuffer to limit the number of bytes to retrieve, the retrieved data is truncated. To
avoid truncating long data, set the value equal to the largest data type size that your
applications need to read.
The longbuffer keyword applies to all databases defined in [oragtwy] section. You cannot
specify a longbuffer value larger than the maximum size for the data type to be retrieved.
Maximum value for this setting is dependent on your operating system and database
server environment..
Example longbuffer=65536
Note: You can also set this environment variable in your SQLWindows application using the
SqlSetParameterAll with the DBP_LONGBUFFER parameter. (Refer to the SQLWindows Function
Reference and the online help for more information about this function and the parameter.)
71
nodefparse
This keyword enables or disables deferred parsing.
Sections [oragtwy]
Default no
Syntax nodefparse={yes|no}
Description This keyword (a shortened form of “no deferred parse”) enables or disables deferred
parsing.
SQLRouter/Oracle uses deferred parsing for improved performance at runtime. However,
deferred parsing makes debugging more difficult because the router cannot return the
position of a column that may have generated an error.
You should especially disable deferred parsing when debugging complex SQL statements
with many columns in the result set. If deferred parsing is disabled and an error is raised,
the cursor automatically highlights the offending column in the result set.
When you put an application into production, you should enable deferred parsing.
Example This example disables deferred parsing.
nodefparse=yes
remotedbname
This keyword specifies database names and their associated connect strings.
Section [oragtwy]
Syntax remotedbname=db_name,connect_string
Description db_name specifies the value you will use as SqlDatabase for SqlConnect()
connect_string is the character “@” followed by the Oracle “Service Name” as
understood by SQL*Net. Only use the first portion of the service name, not the “.world”
portion.
Example This example assumes you have configured your Oracle 7 or Oracle 8 client for an Oracle
Service Name of ARTHUR.world.
Remotedbname=ART,@ARTHUR
You assign the variable SQLDatabase to the value “ART” and then issue the SqlConnect()
call. SqlRouter Oracle finds all of the necessary connection information and connect you
to the Oracle server.
Additional Requirements:
SqlRouter/ Oracle depends upon the Oracle Call Interface (OCI). This lets
SQLRouter/Oracle communicate effectively with versions 7.1, 7.2, 7.3, 8.0.x, 9.x, and
future versions of Oracle. To make sure the proper version of Oracle’s “OCI” software is
used, the registry key HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE contains a value for
the parameter ORAOCI. This can be set to a specific verson of Oracle’s DLL:
Oracle 8.1.X ORACLIENT8.DLL
Oracle 9.2.0.1 ORACLIENT9.DLL
72
Make sure the fully qualified path name is used in the registry entry.
Refer to the Oracle documentation for more information about CONFIG.ORA,
TNSNAMES.ORA, and ORACLE.INI and how to set up these files.
Oracle versions earlier than 8.1.5 are not supported by SqlRouter/Oracle.
Note For related information, see “Connect Search Order” on page 14.
substitute
This keyword specifies that the string in the first parameter should replace the string in the second
parameter whenever the first parameter appears in an SQL statement.
Section [oragtwy]
Syntax substitute=original_string,substitute_string
Description You can have an unlimited number of substitute statements in the initialization file.
However, this statement changes all occurrences of the replaced word in your SQL
statements: operators, WHERE clauses, object names, and literals (but not bind
variables).
The second string can include the first, as in:
substitute=od,odd
The strings can include embedded blank spaces, but not commas. You must use a comma
to separate original_string from substitute_string.
Notes Because each SQL statement is parsed, having substitute statements in your SQL.INI file
adds a small amount of overhead to the compilation of those statements. If you are not
running any Gupta software that require substitution, you may want to remove these
statements from the file.
If you use applications that rely on the “CATALOG” commands, such as Quest, Report
Builder, and DB Explorer, you must include the following statement in your SQL.INI:
substitute=SYSSQL.,
Include this statement exactly as shown with the upper case letters ”SYSSQL” followed by
a period followed by a comma. Without this, Quest, Report Builder, and or DB Explorer
will not be able to use the “CATALOG” commands in your application.
Example This example replaces double quotes, which Oracle does not accept, with nulls. This
statement is useful to run a program or tool you cannot modify that executes in the
Gupta runtime environment and, in certain contexts, places double quotes around names
it sends to the database.
The following statement causes SQLRouter/Oracle to strip off the double quotes before it
sends the data to the database:
substitute=”,
uselob
This keyword specifies whether the SQLBase API should use Oracle Call Interface (OCI) version 8 to work with
LOB datatypes (BINARY LARGE OBJECT and CHARACTER LARGE OBJECT), or use version 7, which cannot
handle LOB datatypes.
73
Default 0
Section [oragtwy]
Syntax uselob=integer
Description The LOB datatypes in Oracle version 9 and greater require the use of OCI version 8. Earlier
versions of the router for Oracle used OCI version 7. If you need compatibility with Oracle
LOB datatypes, set the value of integer to 1 to use OCI 8. If not, set the value to 0 to use
OCI 7. The default is 0.
Note You can also set this environment variable in your SQLWindows application using the
SqlSetParameterAll with the DBP_ORAUSELOB parameter. (Refer to the SQLWindows
Function Reference and the on-line help for more information about this function and
the parameter.)
Stored Procedures
SQLWindows applications can execute PL/SQL stored procedures on an Oracle database. These stored
procedures can also generate trigger events. To execute a PL/ SQL stored procedure, use the
SqlPLSQLCommand function.
A PL/SQL stored procedure invoked by SqlPLSQLCommand can have no more than 254 arguments. Also, the
string used to invoke the procedure cannot contain new line characters, nor can it execute stand-alone
functions. However, the array arguments can be dynamic arrays (see “Dynamic Array Support for PL/SQL
Stored Procedures” on page 76).
The SqlPLSQLCommand cannot process stored procedures without arguments. To execute a stored procedure
without arguments, use SqlPrepareAndExecute; for example:
If NOT SqlPrepareAndExecute(hSql,
'BEGIN anonymous_PL/SQL_block;END;')
SqlPLSQLCommand supports only the following Oracle data types for both scalar and array arguments for
stored procedures:
• NUMBER
• DATE
• CHAR
• VARCHAR
• VARCHAR2
You must explicitly specify the size of CHAR, VARCHAR, or VARCHAR2 data types as arguments to a PL/SQL
stored procedure. You can use either %type or define your own data type. For example, if the stored
procedure takes a CHAR argument that is a value for a column in a table, use %type with
table_name.column_name to declare that variable. If the argument does not tie in with a database column,
you can define MYCHAR CHAR(20), then use %type with MYCHAR to declare your argument.
If you do not specify the size, SQLNetwork binds the arguments with the maximum size allowed for each data
types.
74
Overloading Stored Procedures
SQLRouter/Oracle supports overloaded stored procedures in PL/SQL packages; however, you must:
• Define procedures with greater number of arguments before procedures with fewer arguments.
• Use all the same types in any argument position IN, OUT, or IN/OUT types.
• Use all scalar or array types in any argument position.
You cannot mix data types, nor can you use the DATE type in arguments for overloaded procedures.
For general information about stored procedures, see “Stored Procedures” on page 26.
SqlPLSQLCommand
Use this function to execute PL/SQL stored procedures in your SQLWindows application. Call it once for each
invocation of PL/SQL.
Syntax bOk = SqlPLSQLCommand(hSql, strCommand)
Parameters hSqlHandle—The connected SQL handle to an Oracle database.
strCommand—Command string used to invoke a PL/SQL procedure.
Description The first parameter identifies the SQL handle to the database. The second parameter is a
command string used to invoke a PL/SQL stored procedure. Like a stored procedure call,
this command string must have a name.
You can use PL/SQL IN variables the same way you use any other parameter in SAL
function calls.
PL/SQL OUT or IN/OUT variables must be valid SAL Receive parameters. These
parameters, like SAL Receive parameters, are set when the call returns.
You can use arrays for IN, OUT, and IN/OUT parameters.
IN/OUT parameters can be made to pass data to the PL/SQL stored procedure and to
receive data from a PL/SQL stored procedure in the same parameter.
Return Value bOk is TRUE if the function succeeds and FALSE if it fails.
75
END INVOICES;
CREATE or REPLACE PACKAGE BODY invoices AS
next_invoice_id NUMBER;
PROCEDURE insert_invoice
(o_invoice_id OUT invoice_master.invoice_id%TYPE,
i_client_name IN invoice_master.client_name%TYPE,
i_invoice_date IN invoice_master.invoice_date%TYPE,
i_item_no IN item_no_tbl,
i_quantity IN quantity_tbl,
i_amount IN amount_tbl,
i_num_details IN NUMBER) IS
BEGIN
SELECT INVOICE_SEQ.NEXTVAL INTO next_invoice_id FROM DUAL;
o_invoice_id:=next_invoice_id;
INSERT INTO INVOICE_MASTER
(INVOICE_ID,CLIENT_NAME,INVOICE_DATE)VALUES
(next_invoice_id,i_client_name,i_invoice_date);
FOR n IN 1..i_num_details LOOP
INSERT INTO INVOICE_DETAIL
(INVOICE_ID,ITEM_NO,QUANTITY,AMOUNT) VALUES
(next_invoice_id,i_item_no(n),i_quantity(n), i_amount(n));
END LOOP; COMMIT;
END insert_invoice;
END invoices;
76
Dynamic Arrays as INPUT arguments
Dynamic arrays grow to the size of the largest index value used in an assignment statement using the dynamic
array variables. For example, the following statements cause nDynVar to be a dynamic array of 10 elements:
nDynVar[0] = 0
nDynVar[1] = 1
nDynVar[9] = 9
When you pass a dynamic array as an INPUT argument to a PL/SQL stored procedure using
SqlPLSQLCommand, the number of elements created on the client are available on the database server. For
example, the following stored procedure inserts the value 9 into the table:
insert into foo values(nDynVar[9])
The following statement, however, causes the error “Attempting to fetch beyond end of result set”:
insert into foo values(nDynVar[10])
Uninitialized values
Do not initialize dynamic arrays. The arrays are passed as NULL for data types STRING and DATE/TIME, and
as zero for data type NUMBER. To pass NUMBER as a NULL, the user must explicitly assign it the value
Number_Null.
Uninitialized values
Values for output arguments are not initialized on the backend, but are returned as NULL values.
77
Writing RAW Data
To INSERT or UPDATE columns that contain RAW data, you must first assign the data to be placed in that
column to an appropriate bind variable, then prepare an INSERT or UPDATE statement using that bind
variable.
The bind variable must be of type LONG STRING. Once you have prepared the INSERT or UPDATE statement,
you must call SqlSetLongBindDatatype to bind the LONG STRING data to the RAW data type. You then execute
the INSERT or UPDATE statement.
Note: You must prepare the INSERT or UPDATE statement without executing it, then call
SqlSetLongBindDatatype, then execute the INSERT or UPDATE statement. The binding done by
SqlSetLongBindDatatype lasts only until your application prepares the next SQL statement.
The call to SqlSetLongBindDatatype takes two arguments: the first is the ordinal position of the bind variable
that has the LONG STRING data in the INSERT or UPDATE statement; the second is the constant 23—this
constant denotes RAW data in the case of Oracle databases. (You can declare a user constant with a symbolic
name like nRaw and assign it the value 23; this makes your code more self-documenting.)
For example, assume an Oracle table called PRODUCT with the following column data types:
• INTEGER —for style ID information
• VARCHAR(30) —for style information
• VARCHAR(254)—for description information
• DEMICAL(8,2)—for price information
• LONG RAW—for picture information
The example would work just the same if the last column’s datatype were CHARACTER LARGE OBJECT or
BINARY LARGE OBJECT instead of LONG RAW.
Also assume the following variable declarations in your application:
Number: nStyleId
String: strStyle
String: strDesc
Number: nPrice
Long String: lstrPicture
Now assume you assigned these variables values in your program. You can add a row to the PRODUCT table
as follows:
Set strStmnt=’INSERT INTO PRODUCT VALUES’
Set strStmnt=strStmnt || ‘(:nStyleId,:strStyle,:strDesc,’
Set strStmnt=strStmnt || ‘:nPrice,:lstrPicture)’
Call SqlPrepare(hOracle,strStmnt)
Call SqlSetLongBindDatatype(5,23)
Call SqlExecute(hOracle)
The first argument to SqlSetLongBindDatatype is 5 because :lstrPicture is the bind variable that has the data
to be inserted into the LONG RAW column, and it appears as the fifth bind variable in the INSERT statement.
The second argument must be 23 (or a symbolic integer constant you define yourself that has that value).
78
Chapter 6 – Connecting to Sybase
This chapter describes how to connect SQLWindows applications to Sybase. For the specific versions of
Sybase supported, please refer to the Release Notes.
It is recommended that you read all of Chapter 1 – Overview and Chapter 2 – Initializing and Testing Your
Connection before you read this chapter.
You connect SQLWindows applications to a Sybase server using the native router, SQLRouter/Sybase.
Note: By default, DDL (Data Definition Language) statements, such as CREATE TABLE, are not valid within a
transaction. However, your Sybase database administrator can configure the database to allow some
DDL statements as part of a transaction.
Even if you enable autocommit, you can still precede a specific sequence of SQL statements with the BEGIN
TRANSACTION statement and follow them with a COMMIT (or ROLLBACK) statement. The statements in
between BEGIN TRANSACTION and COMMIT are not committed until the COMMIT is executed. And they are
rolled back if ROLLBACK is executed. Bracketing statements in this way allows you to suppress autocommit for
those statements.
Important: Use the sybautocommit keyword to enable or disable autocommit; do not use the Transact-SQL
SET statement.
For background information on autocommit, see “Autocommit” on page 12.
Bind Variables
Sybase System 11.x and later versions provide native support for pre-compiled commands, and hence, input
bind variables.
For general information about bind variables, see “Bind Variables” on page 13. There are certain limitations
on how you can use bind variables with Sybase.
79
For example, the following SQL statement fails because you cannot use a bind variable to specify a table
name:
Call SqlPrepare(hSql,
‘INSERT INTO :dfTabName VALUES(1)’)
Call SqlExecute(hSql)
Note: If you have existing applications that worked with a Sybase database prior to System 11.x, you may
have code like this that you will have to change.
SQLRouter/Sybase implements the native input bind variable support of Client-Library and SQL Server
whenever possible. This includes the following:
• SELECT
• INSERT
• UPDATE (except positioned UPDATEs)
• DELETE (except positioned DELETEs)
In all other cases (stored procedures, DDL, and so on), bind variable support is simulated through substitution
of bind variable values just prior to execution. Unlike native bind variables, input bind variables are supported
merely as a programming convenience, not as a way of improving performance.
For example, say that dfInput has the value 231 and the code is the following:
Call SybPrepareProc(hSql,’sp_foo @var1 = :dfInput’,
‘:dfInput’)
Call SqlExecute(hSql)
It sends the following SQL statement to the database server:
sp_foo @var1 = 231
Important: For maximum portability, avoid using bind variables that are not ANSI-compliant.
COMPUTE Clause
SQLRouter/Sybase does not support the Transact-SQL extension of COMPUTE. Any query containing a
COMPUTE clause returns error #32028:
COMPUTE clause not supported.
Also, any COMPUTE results from stored procedures can result in a premature END-OF-FETCH.
Data Types
The following table shows the mapping between the data types supported by a SQLWindows application and
the data types supported by a Sybase database server:
Note: To write more than 31,997 bytes of IMAGE or 64,000 bytes of TEXT data, you must call the function
SybWriteText (see “Writing and Retrieving IMAGE and TEXT Data” on page 106).
Empty Strings
On Sybase, if you try to insert the empty string into a varying-length character string column (or try to update
such a column with the empty string), the database stores a space instead.
For background information, see “Nulls, Empty Strings, and Spaces” on page 21.
Error Processing
SQLRouter/Sybase derives its error code and text from one of three possible sources: the SQLWindows file
ERROR.SQL, Client-Library messages, or database messages. SQLRouter/Sybase can receive multiple
messages; it evaluates all the messages and tries to report only the one that is most informative.
As a result, the first message returned by SybGetClientMsg or SybGetServerMsg does not necessarily match
the error code and text that SQLRouter/Sybase reports to the application. (For more information on
SybGetClientMsg and SybGetServerMsg, see “Retrieving Error and Info Messages” on page 83.)
A separate message buffer is created for each connection associated with a given application, database name,
and user name. All SQL handles on the same connection share this single message buffer. The message buffer
is cleared whenever a new SQL command is sent to the database server using one of the SQL handles
associated with the connection.
The number of messages that can be saved is limited. Each saved message consumes a small amount of fixed
overhead, limiting the total number of saved messages to 5000. Attempts to save more than 5000 messages
are ignored. All message text for any single command must fit within 64,000 bytes; otherwise, the saving of
messages is suspended.
The formula for calculating memory consumption is:
nMemory = (nMaxMessages * (nMaxLength + 22))
* nConnections
Error Precedence
With few exceptions (for example, connection failure or results pending), Client-Library messages usually
indicate a problem with SQLRouter/Sybase or Client-Library itself.
When multiple sources are possible for reporting an error condition, the source is based on the following
order of precedence:
• SQLWindows runtime error code (0–32,767)
• Sybase message (0–65,536)
• Client-Library message (0–65,536)
82
All of the error code ranges overlap. To help keep them separate, SQLRouter/Sybase reports the error code to
the application using the following modified ranges:
• SQLWindows runtime error code (0– 19,999)
• • Sybase message (20,000–29,999)
• Client-Library message (30,000–32,767)
Errors greater than 32,767 always return error 32,100; the actual error number appears at the beginning of
the message text.
Note: You can always get the actual error code and text from Client-Library (Sybase) messages by calling the
SQLRouter/Sybase Message API (see “Retrieving Error and Info Messages” on page 83).
RAISERROR
RAISERRORs are user-defined errors typically added to stored procedures. They are considered informational
and non-fatal.
SQLBase Router/Sybase returns different values depending on the value specified in the first RAISERROR
statement that is actually executed in the stored procedure:
• If the value of the first RAISERROR is less than 17,000, then the Sybase backend returns an error.
• If the value of the first RAISERROR is exactly 17, 000, then SqlRouter/ Sybase will return that value plus
any additional RAISERROR values (You have to call SybGetServerMsg () repeatedly to get all of the
RAISERROR values, and the reult set (if any )WILL be returned).
• If the value of the first RAISERROR is greater than 17,000, then SqlRouter/ Sybase will return that value
and any subsequent values of RAISERROR, but WILL NOT return a result set, regardless if one was actually
returned by the Sybase backend.
If you plan to use RAISERROR as a “warning” or as an indicator to direct further logic in your program, then
you should make sure your stored procedure always first has a value of 17,000, an then use additional
RAISERROR statements to indicate different conditions. Your program can check for the first error to be
exactly 17,000 and would then know to look for additional RAISERROR values. At the same time, it could
retrieve the result set from the stored procedure execution . The result set will NOT be available if the
RAISERROR statement specifies any value other than 17,000.
SybGetClientMsgCount
Use this function to return the number of currently buffered client messages.
Syntax bOk=SybGetClientMsgCount(hSql, nCount)
Sql Handle: hSql
83
Receive Number: nCount
Parameters hSql—A handle that identifies a connection context to the database.
nCount—The number of buffered client messages.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Description This function returns the number of client messages currently buffered on handle hSql
in nCount. Messages occupy positions 1 through nCount in the buffer.
Note To enable the buffering of messages, include the sybmaxmessages keyword in the SQL.INI
file.
SybGetClientMsg
Use this function to retrieve the number, text, and severity of an arbitrary client message.
Syntax bOk=SybGetClientMsg(hSql, nPosition, nMsgNumber, strMsgText,
nSeverity)
Sql Handle: hSql
Number: nPosition
Receive Number: nMsgNumber
Receive String: strMsgText
Receive Number: nSeverity
Parameters hSql—A handle that identifies a connection context to the database.
nPosition—The position of the message to be retrieved in the message buffer.
nMsgnumber—The number associated with the retrieved message.
strMsgtext—The text of the retrieved message.
nSeverity—The severity of the retrieved message.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Description This function returns the number, text, and severity of the client message in position
nPosition of the message buffer.
The function fails if the buffer is empty, the end of the buffer has been reached, or you
supply an invalid value for nPosition.
Note To enable the buffering of messages, include the sybmaxmessages keyword in the SQL.INI
file.
SybGetNextClientMsg
Use this function to retrieve the number, text, and severity of the next client message.
Syntax bOk=SybGetNextClientMsg(hSql, nMsgNumber, strMsgText, nSeverity)
Sql Handle: hSql
Receive Number: nMsgNumber
Receive String: strMsgText
Receive Number: nSeverity
84
Parameters hSql—A handle that identifies a connection context to the database.
nMsgnumber—The number associated with the retrieved message.
strMsgtext—The text of the retrieved message.
nSeverity—The severity of the retrieved message.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Description This function returns the number, text, and severity of the next client message in the
message buffer.
The function fails if the buffer is empty or the end of the buffer has been reached.
Note To enable the buffering of messages, include the sybmaxmessages keyword in the SQL.INI
file.
SybGetServerMsgCount
Use this function to return the number of currently buffered server messages.
Syntax bOk=SybGetServerMsgCount(hSql, nCount)
Sql Handle: hSql
Number: nCount
Parameters hSql—A handle that identifies a connection context to the database.
nCount—The number of buffered server messages.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Description This function returns the number of server messages currently buffered on handle hSql.
Messages occupy positions 1 through nCount in the buffer.
Note To enable the buffering of messages, include the sybmaxmessages keyword in the SQL.INI
file.
SybGetServerMsg
Use this function to retrieve the number, text, and severity of an arbitrary server message.
Syntax bOk=SybGetServerMsg(hSql, nPosition, nMsgNumber, strMsgText,
nSeverity)
Sql Handle: hSql
Number: nPosition
Receive Number: nMsgNumber
Receive String: strMsgText
Receive Number: nSeverity
Parameters hSql—A handle that identifies a connection context to the database.
nPosition—The position of the message to be retrieved in the message buffer.
nMsgnumber—The number associated with the retrieved message.
strMsgtext—The text of the retrieved message.
nSeverity—The severity of the retrieved message.
85
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Description This function returns the number, text, and severity of the server message in position
nPosition of the message buffer.
The function fails if the buffer is empty, the end of the buffer has been reached, or you
supply an invalid value for nPosition.
Note To enable the buffering of messages, include the sybmaxmessages keyword in the SQL.INI
file.
SybGetNextServerMsg
Use this function to retrieve the number, text, and severity of the next server message.
Syntax bOk=SybGetNextServerMsg(hSql, nMsgNumber, strMsgText, nSeverity)
Sql Handle: hSql
Receive Number: nMsgNumber
Receive String: strMsgText
Receive Number: nSeverity
Parameters hSql—A handle that identifies a connection context to the database.
nMsgnumber—The number associated with the retrieved message.
strMsgtext—The text of the retrieved message.
nSeverity—The severity of the retrieved message.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Description This function returns the number, text, and severity of the next server message in the
message buffer.
The function fails if the buffer is empty or the end of the buffer has been reached.
Note To enable the buffering of messages, include the sybmaxmessages keyword in the SQL.INI
file.
Examples
To retrieve all messages from the DBCC (Database Consistency Checker) command, you could code the
following:
Call SqlPrepareAndExecute(hSql,’dbcc checkdb’)
! Establish position in message buffer.
If SybGetServerMsg(hSql, 1, nMsgno, strMsgtext, nSeverity)
! Traverse the remaining messages.
Loop
If NOT SybGetNextServerMsg(hSql, nMsgno, strMsgtext, nSeverity)
Break
...
...
Because this is the first time the application traverses the message buffer for this command, the following
example is functionally equivalent:
Call SqlPrepareAndExecute(hSql,’dbcc checkdb’)
! Traverse all the messages.
Loop
86
If NOT SybGetNextServerMsg(hSql, nMsgno, strMsgText, nSeverity)
Break
...
Important: All messages belong to the connection. Individual SQL handles within the same connection access
a single message buffer and inherit their current positioning from any positioning established by prior SQL
handles.
Note: Because each connection consumes certain resources on the client, the actual number of
connections and handles available at runtime can vary.
SQLRouter/Sybase takes advantage of native Sybase cursors to support temporary tables, the SET
database_options statement, and the changing of passwords (with sp_password). For more background
information, see “Handles, Contexts, and Connections” on page 17).
Isolation Levels
Sybase supports isolation levels through the transaction isolation level feature. Level 1 prevents dirty reads.
Level 3 prevents phantom rows. Support for these levels varies according to the version of Sybase.
• Sybase 11.5: SQLRouter/Sybase supports these isolation levels by mapping the SQLWindows isolation
level CS to Level 1 and the isolation level RR to Level 3.
• Sybase11.9.2 and later: Transaction isolation level 2 is explicitly provided for data-only locked tables.
The following table shows the mapping of isolation levels:
87
RO Isolation Level 0 Isolation Level 0
Positioned Updates
Client-Library supports positioned UPDATEs and DELETEs through its native cursor support. Consequently,
SQLRouter/Sybase does not support the FOR BROWSE clause. Use the FOR UPDATE clause in your
SQLWindows applications.
Important: To update IMAGE and TEXT data, you need to use the FOR LONG UPDATE clause (a SQLWindows
extension) instead of the standard FOR UPDATE clause. For more information, see “Writing and Retrieving
IMAGE and TEXT Data” on page 106.
You might code a typical application as follows:
! Disable result set mode; otherwise, we will fetch
! only one row at a time.
SqlSetResultSet(hSql, FALSE)
Note: Unlike FOR BROWSE (which creates a temporary copy of the results set from which rows are fetched),
FOR UPDATE is a true, positioned update operation. “Intent to update” locks are held on the actual
table until EOF or a COMMIT, so you get less concurrency with FOR UPDATE than with FOR BROWSE.
88
Positioned Updates and fetchrow
Rows are fetched in batches sized for the buffers allocated at the network message layer. Handles allow the
application to control the way data is sent across the network. The keyword fetchrow in the SQL.INI file (see
“fetchrow” on page 92) is used to request of the communications layer that it bundle multiple rows of data
per network fetch message back to Net-Library.
SQLRouter/Sybase implements handles for explicit SELECT statements in stored procedures that contain a
single SELECT statement. During positioned UPDATEs and DELETEs, rows are always fetched one at a time.
Therefore, these operations are not affected by the fetchrow setting. Since the client and server must be “in
sync” in terms of current row positioning, permitting multiple rows to be fetched at the network level is not
appropriate. For performance reasons, you typically do not want to use SELECT... FOR UPDATE requests unless
you have very small result sets or you think it likely your application will need to do a positioned update or
delete while fetching rows from a result set.
Note: SQLRouter/Sybase depends on the default locking behavior of the Sybase database (unless the user
explicitly changes this behavior). You should use the SHARE option in your SELECT statements
whenever possible to avoid lock contention.
The more rows your application fetches per message, the longer it takes for control to return to the
application. Thus, users of your application may actually perceive better performance with smaller fetchrow
values, since the application can populate a table window, list box, or other object sooner. Large fetchrow
values can even cause unnecessary rows to be fetched, if the row of interest is located at the beginning of the
result set and the buffer is filled with rows that are eventually discarded.
In general, the larger the fetchrow setting, the faster the result sets can be sent to the client. However, pacing
problems and protocol buffer limits influence the performance level you can expect; at some point you may
even experience performance degradation with a high fetchrow setting. Factors including result set size,
typical row size, network configuration, client and server operating systems, and application requirements, all
affect the optimal setting of this value. You may also need to increase the network packet size (see
“remotedbname” on page 94) to use this feature effectively.
Note: You can set the number of rows retrieved per network message either in the SQL.INI file with the
fetchrow keyword or in your SQLWindows application by calling the function SqlSetParameterAll.
Releasing Locks
You can expedite the releasing of locks on a result set by forcing Sybase to close the result set cursor once you
have fetched the last row from a result set. You enable this behavior using the closecursorateof keyword in
the SQL.INI file (see “closecursorateof” on page 90).
Reserved Strings
The following are SQLRouter/Sybase reserved words, clauses, or names:
89
• CANCEL
• CANCEL ALL
• WITH CURSOR
• _BIN2HEX_
• _HEX_
• FOR LONG UPDATE
For more information about _BIN2HEX_, _HEX_, and FOR LONG UPDATE, see “Writing and Retrieving IMAGE
and TEXT Data” on page 106.
SQL.INI Keywords
This section describes the SQL.INI keywords you want or need to use to initialize a SQLWindows application
that connects to Sybase.
For more information about the SQL.INI file, see “Initializing SQLWindows Applications” on page 28.
checkexists
Use this keyword to get an error after executing an UPDATE or DELETE statement that has no effect.
Section [sybgtwy]
Default off
Syntax checkexists={on|off}
Description This keyword causes SQLRouter/Sybase to return an error when the application executes
an UPDATE or DELETE statement that has no effect (that is, no rows in the database are
updated or deleted). The error that SQLRouter/Sybase returns is #380, “CHECK EXIST
failure”.
Notes If your application calls a stored procedure to execute the UPDATE or DELETE statement
(instead of executing the statement directly), SQLRouter/Sybase cannot determine if any
rows were affected. Therefore, your application will not get the error, even if you set
checkexists to on and no rows were updated or deleted by the stored procedure.
Example This statement causes an application to get the “CHECK EXIST failure” if the application
executes an UPDATE or DELETE statement that affects no rows.
checkexists=on
closecursorateof
Use this keyword to force the closing of a result set cursor once you have fetched the last row from that result
set.
Section [sybgtwy]
Default off
Syntax closecursorateof={on|off}
90
Description If you set this keyword to “off” (or you accept this value by default), you keep the result
set cursor (and your lock on the rows in the result set) until you successfully execute a
COMMIT or ROLLBACK, or until you disconnect from the database.
If you set this keyword to “on” (and CCP is off—see “Cursor Context Preservation” on
page 80), you lose the result set cursor (and your lock on the rows in the result set) once
you have fetched the last row of the result set.
Setting this keyword to “on” allows you to perform DML (Data Manipulation Language)
statements (such as UPDATE, DELETE, INSERT) on the same table from which you have
gotten a result set (with a SELECT statement). If you do not set this keyword to “on”, a
DML statement that operates on that table will fail (time out); this is because the SELECT
statement that got the result set in the first place still has a lock on that table.
Example This example (assuming CCP is off) causes the cursor in a result set to be closed once the
last row from that result set has been fetched; this releases the lock on the table from
which you got the result set.
closecursorateof=on
comdll
Identify the SQLRouters available between SQLWindows (or a client application created with SQLWindows)
and the database.
Section [win32client.dll]
Syntax comdll=communication_dll_name
Description This keyword identifies the filename of a SQLRouter DLL. You can put more than one
comdll statement in the SQL.INI file. The value of communication_dll_name to use for
SQLRouter/Sybase is sqlsyb32.
Example comdll=sqlsyb32
Notes For related information, see “Connect Search Order” on page 14.
enablemultipleconnections
Use this keyword to force the creation of a new connection to the database for each call to SqlConnect.
Section [sybgtwy]
Default off
Syntax enablemultipleconnections={on|off}
Description If this keyword is set to “on”, you get a new connection to the database each time you
call SqlConnect, even if the SQL handle argument to SqlConnect is associated with the
same user ID, password, and database name as one of the already connected SQL
handles.
If this keyword is set to “off”, and you have already called SqlConnect at least once, you
may or may not get a new connection to the database when you call SqlConnect again.
You do not get a new connection if the SQL handle argument in the call is associated with
the same user ID, password, and database name as one of the already connected SQL
handles; otherwise, you do get a new connection.
91
Example This example forces the creation of a new connection to the database for each call to
SqlConnect.
enablemultipleconnections=on
fetchrow
This keyword specifies the maximum number of rows SQLRouter/Sybase retrieves for each network message
during cursor operations (fetching) on a result set.
Section [sybgtwy]
Default 20
Syntax fetchrow=number_of_rows
Description number_of_rows must be a positive integer (but do not put a plus sign).
The server uses an array to hold the fetched column values. SQLRouter/Sybase retrieves
rows for each network fetch requested, according to the following algorithm:
1. Take the width of the widest column and divide it into the maximum size of the array
buffer.
2. If the calculated value is smaller than the value of fetchrow, use the calculated value.
3. Otherwise, use the value of fetchrow. If no value is defined, use the default value of
20.
The value assigned to fetchrow is not used if:
– You use the FOR UPDATE clause in a SELECT statement (CURRENT OF cursor).
– You specify a LONG column in the SELECT list.
You can improve performance by assigning a suitable value to fetchrow. To achieve good
performance, you must balance the number of rows per fetch (which increases the
memory used) against the operating system’s need for memory (which causes the
operating system to swap memory when not enough is available).
Your SQLWindows application still receives a single row for each call to SqlFetchNext,
regardless of the value assigned to fetchrow.
Example This example indicates that only 10 rows are retrieved for each fetch.
fetchrow=10
The following example indicates that you want to fetch only a single row (in effect,
disabling the feature).
fetchrow=1
locktimeout
Use this keyword to set the number of seconds SQLRouter/Sybase waits for Sybase to respond to a login
request or execute a statement.
Section [sybgtwy]
Default 60 second wait for login; infinite wait for statements to execute
Syntax locktimeout=number_of_seconds
92
Description This keyword sets the login time-out and the statement execution time-out to
number_of_seconds. SQLRouter/Sybase will wait number_of_seconds to obtain a server
connection (login time-out). SQLRouter/Sybase will also wait number_of_seconds for the
server to obtain the resources it needs to execute a statement (statement execution
time-out).
If you set number_of_seconds to zero, SQLRouter/Sybase uses the default values of 60
seconds for the login time-out, and infinity (wait forever) for the statement execution
time-out.
When the time-out expires, SQLRouter/Sybase notifies Sybase to abandon the attempt to
connect (login time-out) or the attempt to execute the statement (statement execution
time-out).
Notes This keyword sets the time-out value for any SQLWindows application and for all
connections the application makes to Sybase. To set (or override) the time-out value in
your application, call SqlSetParameter with the DBP_LOCKWAITTIMEOUT argument, or
call SqlLockWaitTimeout.
Example The following example sets the login time-out and the statement execution time-out to
three minutes:
locktimeout=180
log
Use this keyword to activate the SQLRouter activity log.
Section [win32client.syb32]
Syntax log=fully_qualified_file_name
Description You can specify any path or filename for the keyword. If the file already exists, it is
overwritten. Once the keyword is specified, logging is performed automatically with each
SQLRouter initialization. You can apply one or more of the following case-sensitive
options to customize the output:
/Bx—exclude display of bind variable values
/Fa—append to existing file
/FD—display fetch data
/Ld—display LONG data read/written
/Tx—exclude display of timestamps
Enter the options exactly as shown, keeping upper-case letters in upper case and lower-
case letters in lower case.
Example The following example results in a log file that does not include timestamps on entries
(conserving space) and displays the input and output of all LONG (that is, TEXT or IMAGE)
data items.
[winclient.syb32]
log=c:\gupta\sybsys11.log /Tx /Ld
93
longbuffer
This keyword specifies the maximum number of bytes of long data type columns to retrieve or send, and
truncates excess bytes.
Sections [sybgtwy]
Default 32768. Setting a value less than the default will cause the value to be reset to the default.
Syntax longbuffer=number_of_bytes
Description The maximum size of this keyword is limited only by operating system constraints.
Reduce the value of this keyword to conserve memory or reduce network traffic. If you
use longbuffer to limit the number of bytes to retrieve, the retrieved data is truncated. To
avoid truncating long data, set the value equal to the largest data type size that your
applications need to read.
The longbuffer keyword applies to all databases defined in the [sybgtwy] section. You
cannot specify a longbuffer value larger than the maximum size for the data type to be
retrieved.
Example longbuffer=65536
Important: You can also set this environment variable in your SQLWindows application. If
you do, call SqlSetParameterAll with the DBP_LONGBUFFER parameter. Do not set the
size of this buffer with the Transact-SQL SET statement.
remotedbname
Use this keyword to specify database names and associated information.
Section [sybgtwy]
Syntax remotedbname=db_name1,server,db_name2,network_packet_size
Description db_name1 specifies the database name as it is known by the SQLWindows application;
the name may not be more than 8 characters long.
server specifies the name of the Sybase server on which the database is located. The
server name can be found in the Sybase SQL.INI file located in the Open Client installation
subdirectory.
db_name2 specifies the actual database name as known by the server. This parameter is
optional; if you omit it, the name of the database is assumed to be the same as
db_name1. Unlike db_name1, the value of db_name2 is not limited to 8 characters.
network_packet_size is an optional parameter that specifies the network packet size to
use for this server connection. If you omit this parameter or give it a value of zero, the
connection uses the default network packet size negotiated between Client-Library/Net-
Library and the server during connect processing.
Notes For related information, see “Connect Search Order” on page 14.
Examples This example specifies a database known by your SQLWindows application as PUBS. This
database is located on the server SYBASE11. The server knows this database as pubs2.
The network packet size is the default negotiated between Client-Library and the server.
remotedbname=PUBS,SYBASE11,pubs2,0
The following example differs from the preceding one in that SQLRouter/Sybase requests
94
a network packet size of 2048 bytes when it tries to connect to the database.
remotedbname=PUBS,SYBASE11,pubs2,2048
substitute
Use this keyword to specify that the string in the first parameter should replace the string in the second
parameter whenever the first parameter appears in an SQL statement.
Sections [sybgtwy]
Syntax substitute=original_string,substitute_string
Description Values for this keyword are case-sensitive and are separated by a comma (not a space).
You can have an unlimited number of substitute statements in the initialization file.
However, this statement changes all occurrences of the replaced word in your SQL
statements—operators, WHERE clauses, object names, and literals (but not bind
variables).
The second string can include the first, as in the following:
substitute=od,odd
Important: The strings can include embedded blank spaces, but not commas—you must
use a comma to separate original_string from substitute_string.
Notes Because each SQL statement is parsed, having substitute statements in your SQL.INI file
adds a small amount of overhead to the compilation of those statements. If you are not
running any software that require substitution, you may want to remove these
statements from the file.
If you do not want to have any substitutions done, leave this keyword out of the SQL.INI
file or comment out any lines that have this keyword. Dnot have a line that looks like the
following:
substitute=
Example The substitute statement below could be used with an application that (for example)
encloses table names in quotes. If you cannot modify the application, and if the database
you are connecting the application to does not accept double quotes, you can have
SQLRouter strip them off as follows:
substitute=”,
sybapplicationname
Use this keyword to define the client’s application name when logging in to the database server.
Section [sybgtwy]
Default Gupta Sybase App
Syntax sybapplicationname=program_name
Description program_name is stored in the dbo.sysprocesses of the master database for the
connection.
Notes SQLRouter/Sybase defines the reserved identifier @APPNAME as the title of the
application’s top-level window.
Example This statement defines the client application name when logging in to the database
95
server as MYAPP:
sybapplicationname=MYAPP
sybautocommit
Use this keyword to turn autocommit on or off.
Section [sybgtwy]
Default off
Syntax sybautocommit={on|off}
Description To turn on autocommit, set sybautocommit to on; to turn off autocommit, set
sybautocommit to off.
Notes For more information about autocommit, see “Autocommit and Chained Transactions” on
page 79.
You can also turn autocommit on and off in your SQLWindows applications by calling
SqlSetParameter. For example, to disable autocommit, make either one of the following
calls:
Call SqlSetParameter(hSql,DBP_AUTOCOMMIT,FALSE,strNull)
Call SqlSetParameterAll(hSql,DBP_SYBAUTOCOMMIT,FALSE,strNull,TRUE)
Calling either of these functions overrides the value of the sybautocommit keyword in
the SQL.INI file.
Example This statement enables autocommit.
sybautocommit=on
sybmaxmessages
Use this keyword to instruct SQLRouter/Sybase how to save routine messages sent from the server.
Section [sybgtwy]
Default 0,0
Syntax sybmaxmessages=max_messages,max_length
Description max_messages specifies the maximum number of messages to be saved.
max_length specifies the maximum length of a saved message; this parameter is
optional. Any message text beyond the specified limit is truncated. If you do not specify
max_length, the default of 1024 bytes (full message length) is assumed.
Note: Message length is always preserved in favor of message count.
Example The following example saves a maximum of 30 messages, and limits each message to 100
bytes. These settings limit the amount of memory used to store messages to 3660 bytes.
sybmaxmessages=30,100
The following example saves a maximum of 300 messages with full message length (1024
bytes). These settings limit the amount of memory used to store messages to 313,800
bytes. Because the message buffer is limited to much less (64,000 bytes), the actual
number of messages saved may be considerably less than 300. The number saved will
96
depend on the size of the messages.
sybmaxmessages=300
The following example saves a maximum of 30 messages and discards all message text.
Only the message number and severity level are saved. These settings limit the amount
of memory used to store messages to a mere 660 bytes.
sybmaxmessages=30,0
sybtracefile
Use this keyword to invoke the Client-Library trace facility for debugging.
Section [sybgtwy]
Syntax sybtracefile=c:\sybase\sybase.log
Description The trace file can produce information useful to Sybase Technical Support when a
problem occurs in a Sybase software component. The trace file is automatically
configured to dump all available debugging information.
The trace file can quickly grow quite large. It also requires that the debugging version of
Client-Library be installed. If the debugging version is not found during the first LOGIN
attempt, SQLRouter/Sybase generates a dialog box reporting the error and continues
with tracing disabled.
Notes If you do not want to do any tracing, leave this keyword out of the SQL.INI file or
comment out any lines that have this keyword. Do not have a line that looks like the
following:
sybtracefile=
sybworkstationname
Use this keyword to define the machine name by which clients identify themselves.
Section [sybgtwy]
Default workstation_name
Syntax sybworkstationname=hostname
Description hostname is stored in the connection entry of the dbo.sysprocesses of the master
database. You can display it within certain system stored procedures (for example,
sp_who) whenever you have a live connection to the server.
SQLRouter/Sybase defines the reserved identifier @WORKSTATION as the name of the
client computer
If you do not specify a value for this keyword, the literal value used is workstation_name.
Example This statement defines the client machine name as MYHOST:
sybworkstationname=MYHOST
yieldonservercall
Use this keyword to enable and configure asynchronous processing for applications that connect to a Sybase
server using SQLRouter/Sybase.
97
Section [sybgtwy]
Default 0
Syntax yieldonservercall=numeric_ value
Description numeric_value must be an integer between –60 and 600 inclusive.
Asynchronous processing allows a SQLWindows application to send requests to the
Sybase server for processing and periodically poll for a response. In between polls, the
application can either do other work or yield to the operating system (Microsoft
Windows ) to allow other tasks to run. A special function (the callback function)
determines what the application does between polls. SQLWindows defines a default
callback function for you; this function yields to the operating system.
If you disable asynchronous processing, your SQLWindows application does not return
control to the operating system between the time the application sends a request to the
server and the time it receives a reply.
To disable asynchronous processing, set yieldonservercall to zero (or comment out the
statement). To enable asynchronous processing, set yieldonservercall to a non-zero value
in the range from -60 to 600.
A non-zero value defines a polling interval for SQLRouter/Sybase. A positive value defines
a minimum polling interval measured in tenths of a second; a negative value defines a
maximum polling interval measured in seconds. After each polling request,
SQLRouter/Sybase invokes the callback function.
If you assign a positive value to yieldonservercall, you are specifying the minimum time
interval between polling requests. Upon every return from the callback function,
SQLRouter/Sybase determines whether the minimum time interval has passed. If so,
SQLRouter/Sybase polls for a response from the server; if not, SQLRouter/Sybase returns
immediately to the callback function.
If you assign a negative number to yieldonservercall, you are setting the maximum polling
interval to the absolute value of this number; it is SQLRouter / Sybase that determines
the actual polling frequency for you. SQLRouter/Sybase polls very often initially (about
twice a second), but the polling interval quickly increases over time, up to the maximum
value you set. This algorithm assumes that, over time, a response time of perhaps even
several seconds becomes far less significant relative to the total time required to fulfill
the request. Reducing unnecessary polling improves the responsiveness of the
environment and reduces network traffic generally.
Under most circumstances, a setting of +10 (1 call/second) or –5 (dynamic polling interval
with a maximum of 5 seconds) permits reasonable response time and smooth control of
the operating environment. You should use these values if you assume that any task
which gains control during the callback function returns control to SQLRouter/Sybase in a
timely manner, and that the callback function yields to the operating system. (Like any
other application, SQLRouter/Sybase must wait for return of control from the callback
function before it can poll the database server again.)
98
Stored Procedures
You can call stored procedures, execute them on Sybase, and retrieve results sets and return status from
them by using the following SAL functions in your SQLWindows application. These functions are:
• SybExecuteProc on page 6-29
• SybExecuteProcEx on page 6-30
• SybGetNextResults on page 6-31
• SybGetReturnStatus on page 6-32
• SybPrepareNextResults on page 6-34
• SybPrepareProc on page 6-33
You can also execute stored procedures using, for example, SqlPrepare and SqlExecute. However, you should
do this only for stored procedures that do not return result sets. When you execute a stored procedure by
calling SqlPrepare and SqlExecute, SqlPrepareAndExecute, and so on, any result sets that the stored
procedure might return are discarded.
Stored procedures can perform all the usual SQL operations, including positioned updates.
For some general information on stored procedures, see “Stored Procedures” on page 26.
99
If CCP is off, and you call SqlCommit (or execute the COMMIT statement), you implicitly cancel pending result
sets on all SQL handles on the same connection, not just the handle specified as an argument to the function.
For example, the call below does not cancel pending result sets just for hSqlA, but for all other open SQL
handles on the connection (assuming CCP is off).
Call SqlCommit(hSqlA)
Like COMMIT, a ROLLBACK implicitly cancels all pending result sets on all SQL handles (provided CCP is off).
For example, the call below does not cancel pending result sets just for hSqlA, but for all other open SQL
handles on the connection.
Call SqlPrepareAndExecute(hSqlA,’rollback’)
Closing the connection also cancels all pending result sets.
Important: If CCP is on, preparing a new statement on a given SQL handle, or executing a CANCEL, COMMIT,
or ROLLBACK cancels just the result set associated with the SQL handle you specify, not all the result sets for
all of the SQL handles on the same connection.
SybExecuteProc
Use this function to execute a stored procedure or a sequence of SQL statements.
Syntax bOk=SybExecuteProc(hSql, strStatements, strIntoList)
Sql Handle: hSql
String: strStatements
String: strIntoList
Parameters hSql—A handle that identifies a connection context to the database.
strStatements—The stored procedure or SQL statements to be executed.
strIntoList—The list of INTO variables into which the stored procedure’s result set values
(if any) are returned.
Description SybExecuteProc executes the stored procedure or sequence of SQL statements specified
in strStatements. It stops at the first SELECT statement (if any) and returns the result set
from that statement—call SqlFetchNext repeatedly to retrieve the rows in the result set.
If the stored procedure returns additional result sets, call SybGetNextResults once for
each additional result set.
Separate the variables listed in strIntoList with commas and precede each variable name
with a colon. If the stored procedure returns zero rows, the variables in strIntoList keep
whatever values they had before the call to SybExecuteProc. If you know the stored
procedure does not execute any SELECT statements (that is, it does not return any result
sets), specify the value strNull for strIntoList.
If the stored procedure accepts input parameters, you can specify literals, constants, or
bind variables (of any type except LONG STRING) as input arguments.
Note: Even though you cannot specify a LONG STRING bind variable as an input
parameter to a stored procedure, there is one exception: you can specify a bind variable
assigned a string of exactly 255 bytes.
If the stored procedure returns values in output parameters, you must supply output
arguments in order to call the procedure. However, you cannot retrieve the values of the
output arguments. SQLRouter/Sybase does not support returning the values of output
parameters from a stored procedure to your SQLWindows application.
100
Note: You can work around this restriction (see “Retrieving Output Parameter Values” on
page 104).
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Examples This function is demonstrated in the sample application SQLSYBS3.APP.
SybExecuteProcEx
Use this function to execute a stored procedure or a sequence of SQL statements when you do not know if
the stored procedure returns any result sets.
Syntax bOk=SybExecuteProcEx(hSql, strStatements, strIntoList, bRows)
Sql Handle: hSql
String: strStatements
String: strIntoList
Receive Boolean: bRows
Parameters hSql—A handle that identifies a connection context to the database.
strStatements—The stored procedure or SQL statements to be executed.
strIntoList—The list of INTO variables into which the stored procedure’s result set values
(if any) are returned.
bRows—Flag that indicates whether the stored procedure is able to return rows (but not
whether any rows are actually returned).
Description When SybExecuteProcEx is called, it causes all statements in the stored procedure up
through the first SELECT statement to be executed, then returns the result set from that
SELECT statement. Call SqlFetchNext repeatedly to fetch the rows in the result set, then
call SybGetNextResults to execute the next statements in the stored procedure up
through the next SELECT statement.
Separate the variables listed in strIntoList with commas and precede each variable name
with a colon. If the stored procedure returns zero rows, the variables in strIntoList keep
whatever values they had before the call to SybExecuteProcEx.
The parameter bRows is set to TRUE if the stored procedure executes at least one SELECT
statement (even if the statement returns zero rows). If the stored procedure does not
execute a SELECT statement, bRows is set to FALSE.
If the stored procedure accepts input parameters, you can specify literals, constants, or
bind variables (of any type except LONG STRING) as input arguments.
Note: Even though you cannot specify a LONG STRING bind variable as an input
parameter to a stored procedure, there is one exception: you can specify a bind variable
assigned a string of exactly 255 bytes.
If the stored procedure returns values in output parameters, you must supply output
arguments in order to call the procedure. However, you cannot retrieve the values of the
output arguments. SQLRouter/Sybase does not support returning the values of output
parameters from a stored procedure to your SQLWindows application.
Note: You can work around this restriction (see “Retrieving Output Parameter Values” on
page 104).
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
101
Example This example stores a procedure on Sybase, then executes that stored procedure while
checking if the procedure returns result sets.
Call SybExecuteProc(hSql,
‘create procedure authorproc @switch int as if @switch = 1
select au_lname from authors
else
update authors set au_lname = \’dummy\’
where au_lname = \’cognoscente\’’,’’)
Call SybExecuteProcEx(hSql,’exec authorproc 1’,’:df1’,bRows)
If bRows
Call SqlFetchNext(hSql,nFetchInd)
Call SybExecuteProcEx(hSql,’exec authorproc 2’,’:df1’,bRows)
If bRows
Call SqlFetchNext(hSql,nFetchInd)
Else
Call SalMessageBox(‘Row updated.’,’Procedure Results’,MB_Ok)
SybGetNextResults
Use this function to get the next result set from a stored procedure.
Syntax bOk=SybGetNextResults(hSql, strIntoList)
Sql Handle: hSql
String: strIntoList
Parameters hSql—A handle that identifies a connection context to the database.
strIntoList—The list of INTO variables into which the stored procedure’s result set values
(if any) are returned.
Description Results of stored procedures are returned in one or more sets with zero or more rows in
each set. SybExecuteProc returns the first result set. Use SybGetNextResult to retrieve
subsequent sets. Each set of data is returned in the variables specified by strIntoList.
Separate the variables listed in strIntoList with commas and precede each variable name
with a colon. If the stored procedure returns zero rows, the variables in strIntoList keep
whatever values they had before the call to SybGetNextResults.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Notes Once you retrieve the next result set, call SqlFetchNext repeatedly to fetch each row of
data in the result set.
Example This function is demonstrated in the sample application SQLSYBS1.APP.
SybGetReturnStatus
Use this function to get the return status from a stored procedure.
Syntax bOk=SybGetReturnStatus(hSql, nRetVal)
102
Sql Handle: hSql
Number: nRetVal
Parameters hSql—A handle that identifies a connection context to the database.
nRetVal—The return value from a stored procedure.
Description This function assigns the return status of a stored procedure to nRetVal. You can get the
return status (as defined by Sybase) only after you have fetched the last row of the last
result set returned by the stored procedure.
If you prepare and execute another statement on the same handle (hSql) before calling
SybGetReturnStatus, you can no longer obtain the return status for the stored procedure.
However, you can perform operations on a different SQL handle (including calling
SybGetReturnStatus with a different handle to get the return status of a different stored
procedure) and still come back and get the return status of the stored procedure
associated with hSql.
Return Value bOk is set to TRUE if the return status was available and to FALSE if it was not available. If
bOk is FALSE, the value of nRetVal is undefined.
Example This function is demonstrated in the sample application SQLSYBS1.APP.
SybPrepareProc
Use this function to prepare a stored procedure for execution.
Syntax bOk=SybPrepareProc(hSql, strStatements, strIntoList)
Sql Handle: hSql
String: strStatements
String: strIntoList
Parameters hSql—A handle that identifies a connection context to the database.
strStatements—The statements to be prepared by the database.
strIntoList—The list of INTO variables into which the stored procedure’s result set values
(if any) are returned.
Description Call this function to prepare the statements in strStatements that create or invoke a
stored procedure.
If the stored procedure accepts input parameters, you can specify literals, constants, or
bind variables (of any type except LONG STRING) as input arguments.
Note: Even though you cannot specify a LONG STRING bind variable as an input
parameter to a stored procedure, there is one exception: you can specify a bind variable
assigned a string of exactly 255 bytes.
If the stored procedure returns values in output parameters, you must supply output
arguments in order to call the procedure. However, you cannot retrieve the values of the
output arguments. SQLRouter/Sybase does not support returning the values of output
parameters from a stored procedure to your SQLWindows application.
Note: You can work around this restriction (see “Retrieving Output Parameter Values” on
page 104).
The INTO variables in strIntoList can be of any data type. Separate the variables listed in
103
strIntoList with commas and precede each variable name with a colon. If the stored
procedure returns zero rows, the variables in strIntoList keep whatever values they had
before the call to SybPrepareProc. If you know the stored procedure does not execute
any SELECT statements, specify the value strNull for strIntoList.
To actually create or invoke the stored procedure, you need to execute the prepared
statements. You can do this explicitly (by calling SqlExecute), or implicitly (for example, by
calling SalTblPopulate).
You cannot mix calls to SybPrepareProc with SybGetNextResult, nor SybExecuteProc or
SybExecuteProcEx with SybPrepareNextResults, in the same execution cycle of a stored
procedure. All other functions (for example, SybGetReturnStatus, SybGetError, and so on)
work with either set of functions.
As with SybExecuteProc and SybExecuteProcEx, you are not limited to specifying in
strStatements statements that create or invoke a stored procedure; you can specify any
valid SQL statements in strStatements.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Notes If you do not expect the stored procedure to return result sets, call SqlPrepare instead of
SybPrepareProc.
Example This function is demonstrated in the sample application SQLSYBS3.APP.
SybPrepareNextResults
Prepare the next SELECT statement in a stored procedure.
Syntax bOk=SybPrepareNextResults(hSql, strIntoList, bEndOfResults)
Sql Handle: hSql
String: strIntoList
Boolean: bEndOfResults
Parameters hSql—A handle that identifies a connection context to the database.
strIntoList—The list of INTO variables into which the stored procedure’s result set values
(if any) are returned.
bEndOfResults—Flag that indicates if there are no more result sets.
Description This function prepares the next SELECT statement in the stored procedure; you must then
call SqlExecute with the same SQL handle you specified in SybPrepareNextResults to
actually retrieve the result set. All INTO variable data types are supported.
Separate the variables listed in strIntoList with commas and precede each variable name
with a colon. If the stored procedure returns zero rows, the variables in strIntoList keep
whatever values they had before the call to SybPrepareNextResults.
Return Value bOK is to TRUE if the function succeeds and to FALSE if it fails.
Example This function is demonstrated in the sample application SQLSYBS3.APP.
105
Transactions, Disconnects, and Exits
If autocommit is off in your application, you are responsible for explicitly committing or rolling back
transactions. If autocommit is off, and you disconnect from the database or exit the application (either
normally or abnormally) without committing or rolling back a pending transaction, the database rolls back
the transaction for you.
Writing Data
To write IMAGE or TEXT data of up to 64K, you can use the INSERT or UPDATE SQL statements, but you must
then supply the data as a literal or a constant. You can write IMAGE or TEXT data of any size using the
function SybWriteText; assign the data to a variable and pass that variable as an argument to SybWriteText.
Note: If you attempt to execute an INSERT or UPDATE statement using bind variables on an IMAGE or TEXT
column, the current transaction will be rolled back and you will be presented with the error message
returned by the database server. This is because Sybase does not support dynamic parameters for
TEXT and IMAGE data.
106
3. Commit the insert operation (if autocommit is off) specifying the handle hSql1.
4. Turn off result set mode (specifying the handle hSql1). To preserve the cursor context, turn on CCP
before turning off result set mode.
5. Execute a SELECT…FOR LONG UPDATE statement, specifying hSql1. (The FOR LONG UPDATE clause is an
extension to SQL that SQLWindows uses for Sybase only.)
6. Position to the desired row.
7. Get another SQL handle (for example, hSql2).
8. Call SybWriteText (using hSql2) to update the row.
To delete IMAGE or TEXT data:
1. Turn on result set mode.
2. Execute a SELECT…FOR UPDATE statement.
3. Position to the desired row.
4. Execute the DELETE statement.
When calling SybWriteText, you can choose whether or not to log the update of the IMAGE or TEXT column
by setting the bLogging argument to this function appropriately. If bLogging is FALSE, the database server will
not log the update. Note that you must enable the sp_dboption option (select into/bulkcopy) on the database
server to perform operations without logging.
Note: It is still possible to encounter trailing spaces for VARCHAR values if the row value itself was INSERTed
or UPDATEd with trailing spaces. SQLRouter/Sybase strips only those spaces that lie beyond the
actual stored length. Consequently, SalStrLength indicates the true length of the data value stored in
the database.
SybWriteText
Perform a positioned update of more than 31,997 bytes of IMAGE data or more than 64,000 bytes of TEXT
data on a Sybase database.
107
Syntax bOk=SybWriteText(hSql,strCursorName,nColumnNum,nColumnName,
strUpdateValue,bTimeStamp,bLogging)
Sql Handle: hSql
String: strCursorName
Number: nColumnNum
String: strColumnName
String: strUpdateValue
Boolean: bTimeStamp
Boolean: bLogging
Parameters hSql—A handle that identifies a connection context to the database.
strCursorName—Name of the cursor associated with the SQL handle on which you
executed the SELECT statement that retrieved the row to be updated.
nColumnNum—Ordinal position in the SELECT statement of the column to be updated.
strColumnName—Fully qualified name of the column to be updated.
strUpdateValue—Value to be written to the column.
bTimeStamp—Flag that indicates whether or not this function should avoid updating the
column if it has been updated since you executed.
bLogging—Flag that indicates whether or not the transaction gets logged.
Description This function performs a positioned update on IMAGE or TEXT data in the column named
in strColumnName. The name in strColumnName must be the fully qualified name of a
column in an actual table, not a view.
You first execute a SELECT...FOR LONG UPDATE statement to retrieve the rows and
columns of interest from the table. You then call SqlFetchNext to fetch rows, and
SybWriteText to update the column strColumnName in the current row.
You can SELECT and update any number of columns. The value in nColumnNum is the
ordinal position of the column listed in the SELECT...FOR LONG UPDATE statement. You
vary this number with each call to SybWriteText to update more than one column in the
current row before fetching the next row.
The SQL handle you pass as an argument to SybWriteText must be different from the SQL
handle used to execute the SELECT...FOR UPDATE statement.
This function assumes the column to be updated is either not NULL, or has been set to
NULL using the UPDATE statement (not the INSERT statement).
To set a TEXT or IMAGE column to NULL, execute an UPDATE statement; do not call
SybWriteText.
Notes You must disable result set mode before call SybWriteText because this function does a
positioned update.
Return Value bOk is set to TRUE if the function succeeds and to FALSE if it fails.
Example The following example illustrates the typical operations that are performed when calling
this function:
! Open both cursors.
Call SqlConnect(hSql1)
108
Call SqlConnect(hSql2)
! Result sets must be off for positioned updates.
Call SqlSetResultSet(hSql1,FALSE)
! Assume a bmptbl table and a bitmap column.
Set strSQLstmt = ‘SELECT bitmap FROM bmptbl FOR LONG UPDATE’
Call SqlPrepare(hSql1,strSQLstmt)
Call SqlOpen(hSql1,‘CURSOR1’)
Loop
If NOT SqlFetchNext(hSql1,nRetVal)
Break
! Assume strNewBitMap has the new data for updating.
Call SybWriteText(hSql2,‘CURSOR1’,1,‘bmptbl.bitmap’,
strNewBitMap,bTimeStamp,bLogging)
109
Chapter 7 – Connecting to Databases Using
ODBC
This chapter explains how to connect SQLWindows applications to databases using ODBC. It also describes
the mapping of error codes between SQLWindows and ODBC.
It is recommended that you read all of Chapter 1 – Overview and Chapter 2 – Initializing and Testing Your
Connection before you read this chapter.
You connect SQLWindows applications to ODBC data sources with the Team Developer ODBC router,
SQLRouter/ODBC. This router conforms to the ODBC 3.0 specification up to core levels 1 and 2 (ODBC 2.0
level within the 3.0 specification).
Note: If you will be connecting to a DB2/4700 data source, make sure to read “Connecting to Access” on
page 7-3. In all other cases, make sure to read the documentation that comes with your ODBC driver.
Your SQLWindows application communicates with SQLRouter/ODBC (supplied with your Team Developer
software); the router talks to the Microsoft ODBC Driver Manager (supplied with Windows); the Driver
Manager talks to the ODBC driver (supplied by a third-party vendor); finally, the ODBC driver talks to the
target database.
ODBC drivers from various vendors are available that work with SQLRouter/ODBC to allow you to connect
your SQLWindows applications to a given data source using ODBC. You need to install and configure an ODBC
driver that has been written to work with the database you want to use. The ODBC driver should also have
been certified to work with SQLWindows applications by the vendor for that driver.
Important: In addition to reading Chapter 2 – Initializing and Testing Your Connection, you must read the
documentation that comes with your ODBC driver to find out what you need to know to connect to your
target database using that driver. The driver documentation should also describe any limitations or special
features of that driver.
Connecting to Access
The Access ODBC driver that we certify does not support isolation levels.
110
Connecting to DB2/400
Your SQLWindows applications connect to DB2/400 just as they would to any other data source. However, you
need to carefully check the documentation that comes with the StarSQL ODBC driver from StarWare, Inc. to
see what kind of support and limitations come with their DB2/400 driver. Topics you should check include
autocommit, cursor context preservation, isolation levels, stored procedures, and transaction processing.
When you update logical files, you must use journaling. Otherwise, you must update using physical files.
See “Cursor Context Preservation” on page 112, “Stored Procedures” on page 121, and “Transactions,
Disconnects, and Exits” on page 121.
For background information on these topics, see “Autocommit” on page 12, “Cursor Context Preservation” on
page 15, “Isolation Levels” on page 19, “Stored Procedures” on page 26, and “Transactions” on page 26.
Note: Your SQLWindows applications can access a SQLBase database in much the same way they access any
other database. However, you cannot use the SQLBase ODBC driver to access SQLBase. See the
SQLBase documentation to learn how to connect a SQLWindows application to SQLBase.
Brand Information
If your SQLWindows application needs to identify the type of database server it is connected to, you call
SqlGetParameter(hSql, DBP_BRAND, nBrand, strNull) to retrieve the brand into the parameter nBrand.
However, if you are connected to an ODBC data source (which is also the case when you connect to Microsoft
SQL Server 6.x), the value returned in nBrand is always 31 (which denotes “ODBC”).
If your application gets the value 31 in nBrand, you need to make additional function calls to get more specific
information. You use these functions to find out the name of the database and ODBC driver, as well as the
version number of the ODBC driver. These function calls are:
• SqlGetParameterAll (hSql, DBP_DRIVER_NAME, nNum, strDriverName)
• SqlGetParameterAll (hSql, DBP_DRIVER_VER, nNum, strDriverVersion)
• SqlGetParameterAll (hSql, DBP_DBMS_NAME, nNum, strDBMSName)
To get the definitions of the constants DBP_DRIVER_NAME, DBP_DRIVER_VER, and DBP_DBMS_NAME,
include the file SQLNWKCN.APL (located in your installation directory) in your application by selecting
Libraries, File Include from the SQLWindows menu bar.
111
Cursor Context Preservation
When a SQLWindows application connects to an ODBC data source, the default state of cursor context
preservation (CCP)—whether it is on or off—is a function of the database to which you connect.
If you attempt to turn CCP on or off in your application, SQLRouter/ODBC passes this request on to the ODBC
driver. For this request to be honored, both the ODBC driver and the data source must support the setting of
CCP at runtime. Read the documentation supplied with your ODBC driver and your database for more
information.
Important: When connecting to a DB2/400 data source using the StarSQL ODBC driver from StarWare, your
application cannot change the setting for CCP. Since CCP is off by default in SQLWindows, this means that CCP
is always off when you connect to DB2/400 using StarSQL.
If CCP is on, you can continue executing SQL statements you have already prepared even after you commit the
operations you have executed. If CCP is off and you execute a COMMIT, you must re-prepare those SQL
statements if you want to re-execute them. Whether CCP is on or off, you must also prepare them again if you
execute a ROLLBACK.
For more background information on CCP, see “Cursor Context Preservation” on page15 .
Data Types
SQLRouter/ODBC maps between the four data types supported in SQLWindows applications and the SQL data
types defined by the ODBC specification. The mapping supports all ODBC SQL data types (minimum, core, and
extended) except SQL_BINARY and SQL_VARBINARY.
SQLWindows ODBC
Important: To learn which data types are supported by the data source you are connecting to using your
ODBC driver, read the documentation that comes with the ODBC driver.
Error Processing
SQLWindows has three standard functions to process errors.
• SqlGetError—Returns an error message.
112
If the error number is less than 20,000, the file ERROR.SQL is searched for the error text and that text (if
found) is returned; otherwise, the translated error number and database error message from the
database server are returned
• SqlErrorText—Searches only ERROR.SQL for error text reason and remedy.
If there is a reason and remedy for the given error number in ERROR.SQL, the reason and remedy are
returned; otherwise, the string “message not found” is returned.
• SqlGetErrorText—Returns an error message.
If the text for the given error number is found in ERROR.SQL, that text is returned; otherwise, the
database error message is returned.
Error messages have the following format:
<native_error>[<vendor>][ODBC_component][data_source]<error_text>
The following is an example:
Microsoft SQL Server:208[Microsoft][ODBC SQL Server Driver][SQL Server] Invalid
object name ’tyu’.
The syntactical components of this example are the following:
• native error—Microsoft SQL Server:208
• vendor—Microsoft
• ODBC component—ODBC SQL Server Driver
• data source—SQL Server
• error text—Invalid object name tyu
01000 20087
01002 20010
01004 20011
01006 20012
01S00 20013
01S01 20090
01S02 20091
113
ODBC Error Code SQLWindows Error Number
01S03 20092
01S04 20093
07001 20014
07006 20015
08001 20016
08002 20017
08003 20018
08004 20019
08007 20020
08S01 20021
21S01 20022
21S02 20023
22001 20024
22003 20025
22005 20026
22008 20027
22012 20028
22026 20029
23000 20030
24000 20031
25000 20032
28000 20033
34000 20034
37000 20035
3C000 20036
114
ODBC Error Code SQLWindows Error Number
40001 20037
42000 20038
70100 20039
IM001 20040
IM002 20041
IM003 20042
IM004 20043
IM005 20044
IM006 20045
IM007 20046
IM008 20047
IM009 20048
IM010 20103
IM011 20104
IM012 20105
IM013 20106
S0001 20049
S0002 20050
S0011 20051
S0012 20052
S0021 20053
S0022 20054
S0023 20107
S1000 20055
S1001 20056
115
ODBC Error Code SQLWindows Error Number
S1002 20057
S1003 20058
S1004 20059
S1008 20060
S1009 20061
S1010 20062
S1011 20108
S1012 20063
S1015 20064
S1090 20065
S1091 20066
S1092 20067
S1093 20068
S1094 20069
S1095 20070
S1096 20071
S1097 20072
S1098 20073
S1099 20074
S1100 20075
S1101 20076
S1102 20077
S1103 20078
S1104 20111
S1105 20112
116
ODBC Error Code SQLWindows Error Number
S1106 20079
S1107 20080
S1108 20081
S1109 20082
S1110 20083
S1111 20113
S1C00 20084
S1DE0 20085
S1T00 20086
Lock Time-Out
You can establish a lock time-out in your SQLWindows application when connecting to a database using
ODBC, provided that both the ODBC driver you are using and the database you are connecting to support
setting a lock time-out from a client application. Read the vendor documentation for your driver and your
database for more information.
SQL.INI Keywords
This section contains the keywords you need or may want to use in the SQL.INI file when connecting a
SQLWindows application to a database using ODBC.
For more information about the SQL.INI file, see “Initializing SQLWindows Applications” on page 28.
buffrow
Use this keyword to control the buffering of data between your SQLWindows application and
SQLRouter/ODBC.
Section [odbcrtr]
Default 0
Syntax buffrow=number_of_rows
Description This keyword controls the buffering of data between your SQLWindows application and
SQLRouter/ODBC. By decreasing the buffrow value, response time can be improved
significantly. Larger values increase data throughput, but lengthen the response time.
117
The values for buffrow can range from 0 through 32767. Assigning a value does not
guarantee that the current INMESSAGE is of sufficient size to fulfill the request. In these
cases, the number of buffered rows may be considerably less.
The default value of zero causes SQLRouter/ODBC to revert to buffering data based on
the number of rows which will fit within the current INMESSAGE buffer size.
Example This statement instructs SQLRouter/ODBC to perform single row fetches into the
INMESSAGE buffer:
buffrow=1
Notes The buffrow keyword has no effect on the manner in which data is buffered and
transported across the network.
You can also configure the buffering of data for individual SQL handles using the
SqlSetParameterAll function. Assuming nBuffrow has already been assigned the value
desired for SQL handle hSql, you can make the following call:
SqlSetParameterAll(hSql,DBP_BUFFROW,nBuffRow,FALSE,TRUE)
comdll
Identify the SQLRouters available between SQLWindows (or a client application created with SQLWindows)
and the database.
Section [win32client.dll]
Syntax comdll=communication_dll_name
Description This keyword identifies the filename of a SQLRouter DLL. You can put more than one
comdll statement in the SQL.INI file. The value of communication_dll_name to use for
SQLRouter/ODBC is sqlodb32.
Notes For related information, read Connect search order on page 1-6.
Example comdll=sqlodb32
enablemultipleconnections
Use this keyword to force the creation of a new connection to the database for each call to SqlConnect.
Section [odbcgtwy]
Default off
Syntax enablemultipleconnections={on|off}
Description If this keyword is set to “on”, you get a new connection to the database each time you
call SqlConnect, even if the SQL handle argument to SqlConnect is associated with the
same user ID, password, and database name as one of the already connected SQL
handles.
If this keyword is set to “off”, and you already called SqlConnect at least once, you may or
may not get a new connection to the database when you call SqlConnect again. You do
not get a new connection if the SQL handle argument in the call is associated with the
same user ID, password, and database name as one of the already connected SQL
handles; otherwise, you do get a new connection.
Example The following example forces the creation of a new connection to the database for each
118
call to SqlConnect:
enablemultipleconnections=on
log
Define the database router activity log and enable logging.
Section [win32client.odb32]
Syntax log=fully_qualified_path_name
Description Specify any valid file pathname after the keyword. If the file does not exist, it is created. If
the file already exists, it is overwritten (unless the /Fa option is specified see below).
Once the log statement has been added to the SQL.INI file, logging is performed
automatically.
You can specify one or more of the options listed below after the fully qualified
pathname to customize the output:
/Bx—exclude bind variable values
/Fa—append to existing file
/FD—display fetch data
/Ld—display LONG data read or written
/Tx—exclude timestamps
Enter the options exactly as shown, keeping upper-case letters in upper case and lower-
case letters in lower case.
Example The following example calls for a log file that does not include timestamps on entries (to
conserve disk space), and displays the input and output of all LONG data (including TEXT
and IMAGE data items):
[win32client.odb32] log=c:\odbc.log /Tx /Ld
longbuffer
Specify the maximum number of bytes of LONG column data to retrieve or send.
Sections [odbcrtr]
Default 32 Kbytes. Setting a value less than the default will cause the value to be reset to the
default.
Syntax longbuffer=number_of_bytes
Description This keyword sets the size of the buffer that holds LONG data. The maximum size is
limited only by operating system constraints. Normally, the optimal size that avoids data
loss is the largest column of LONG data to be sent or retrieved by the SQLWindows
application. A larger buffer uses more memory and increases network traffic; a smaller
buffer uses less memory and reduces network traffic. However, if the buffer is too small
to hold all of the data, the excess is truncated.
If specified, the longbuffer statement applies to all databases connected to using ODBC. It
is recommended that you not specify a value for longbuffer larger than the maximum
LONG column size in any of the tables stored in any of those databases.
119
Example The following statement sets to 64K the maximum number of bytes of LONG column data
to retrieve from or send to any database connected to using ODBC:
longbuffer=65536
Notes You can also set this variable in a SQLWindows program by calling SqlSetParameterAll
with the DBP_LONGBUFFER parameter (defined in SQLNWKCN.APL). This allows you to
tailor the size of the buffer to the application.
odbctrace
Trace all calls to the ODBC API.
Section [odbcrtr]
Default off
Syntax odbctrace={on|off}
Description The ODBC Driver Manager can trace all calls made to the ODBC API. The trace
information is saved in the log file whose pathname is given in the odbtracefile
statement.
Example The following statement enables ODBC API call tracing:
odbctrace=on
odbctracefile
Specify the pathname of the trace file for ODBC API calls.
Section [odbcrtr]
Default client_root_directory\sql.log
Syntax odbctracefile=fully_qualified_filename
Description This keyword specifies the pathname of the trace file for ODBC API calls. This keyword
has no effect unless the odbtrace keyword is set to “on”(see “odbctrace” on page 120).
Example The following statement specifies that the trace file is called odbc.log, and that it is
located in the \logs directory on the client’s c: drive:
odbctracefile=c:\logs\odbc.log
remotedbname
Use this keyword to specify database names and their associated connect strings.
Section [odbcrtr]
Syntax remotedbname=db_name1,connect_string
Description db_name1 specifies the database name as it is known by the SQLWindows application;
the name may not be more than 8 characters long.
connect_string is the exact connect string you will use to connect to the ODBC data
source. Typically, this entry begins with the string "DSN=" to specify the data source
name specified in the ODBC Administrator tool.
The value specified in connect_string can include embedded spaces. Do not put
120
comments on the same line with the "remotedbname" statement. Everything from the
comma following db_name to the end of line is interpreted as the connect string.
Examples: Assume you defined two data sources in ODBC Administrator. One is for Microsoft
SqlServer 7.0 (with a data source name of "MS SqlServer 7.0"), and the other is for a
Visual FoxPro database (with a data source name of "Visual FoxPro DB"). The
remotedbname statements look like:
remotedbname=SS70,DSN=MS SqlServer 7.0
remotedbname=VFP, DSN=Visual FoxPro DB
Your application sets the variable "SqlDatabase" to either "SS70" (to connect to the
SqlServer data source) or to "VFP" (to connect to the FoxPro database), set SqlUser and
SqlPassword appropriately, and issue the SqlConnect() call. SqlRouter/ODBC obtains all
the necessary information from the configuration maintained by the ODBC Administrator
utility.
Additional note: The remotedbname parameter is not necessary for applications built using Team
Developer. It is required if you want to use the SqlTalk utility to connect to the ODBC data
source.
When connecting to any ODBC data source where the data source name was configured
by the ODBC Administrator tool, your application can bypass the remotedbname
parameter altogether, and set the variable SqlDatabase to the actual ODBC data source
name. Using the previous example, if you issue the following statements (assume SqlUser
and SqlPassword are set), your program will connect correctly to the Microsoft SqlServer
7.0 data source without using the remotedbname parameter in SQL.INI:
Set SqlDatabase = "MS SqlServer 7.0" Call SqlConnect (hSql)
Stored Procedures
SQLRouter/ODBC supports calling stored procedures that accept input arguments and return result sets.
However, the router does not support obtaining values from a stored procedure using output arguments.
Syntactically, you can legally call a stored procedure that has output parameters by providing bind variables
where the output arguments are required; however, the value of those variables will be undefined after you
have called the stored procedure, so they will be of no practical use to you.
Important: If your ODBC driver does not support returning values in result sets, such as the StarSQL ODBC
driver for DB2/400, you cannot get information from a stored procedure into your SQLWindows application.
Read your ODBC driver documentation to find out what kind of stored procedure support your driver
provides, and what limitations or restrictions it imposes.
For more information on stored procedures read Stored Procedures in chapter 6.
121
When it comes to Data Definition Language (DDL) statements, such as CREATE TABLE, some databases
commit them as soon as they are executed, regardless of whether autocommit is on or off. For these
databases, the DDL statements cannot be rolled back along with the pending DML statements. Other
databases treat DDL statements just like DML statements. They do not commit them until an explicit COMMIT
is executed. For these databases, the pending DDL statements are rolled back just like the DML statements.
Note: In the case of DB2/400 and the StarSQL driver from StarWare, all the statements in the pending
transaction (both Data Definition Language and Data Manipulation Language statements) are rolled
back.
122
Chapter 8 – Connecting to Multiple
Databases Concurrently
This chapter describes some of the considerations you need to take into account when writing SQLWindows
applications that access multiple databases concurrently.
Overview
SQLWindows is a 32-bit client/server application development environment for Microsoft Windows. Using
SQLWindows and other Team Developer components, teams of programmers can build large, enterprise-wide
client/server applications that connect to, retrieve data from, and manipulate data at database servers from a
variety of vendors.
This chapter describes a sample application that executes transactions against three different database
servers. It tells you how to set up and run the application, it describes some of the major design issues, and it
provides code excerpts to illustrate how different parts of the application were implemented.
Make sure to read “Chapter 1 – Overview” for general information about database server and SQLWindows
features that affect how you write your applications.
Two Approaches
When writing a multi-database SQLWindows application, you have two basic approaches to choose from.
One approach (the one used in the sample application) is to take the SAL language and certain SQLWindows
features and create as much common code as possible for accessing the different databases from different
vendors. These features include dynamic table windows and automatic column variables. The rest of the
application has code specific to the database server being accessed. This approach is easier to understand
conceptually, gives a standard example of a multi-database application, and results in more understandable
code.
The other approach is more object-oriented—use SQLWindows functional classes to handle accessing
heterogeneous databases and maximize the reuse of code. For information on writing multi-database
applications that create and use functional classes, read the white paper Designing Multi-Database
Applications with Gupta Object Classes. You can access this paper by going to the Gupta Technologies home
page at http://www.guptatechnologies.com.
124
Configuring the Application
You must configure the application before connecting to any of the three databases by modifying the SQL.INI
file.
For SQLBase the installation program modifies the SQL.INI for you.
For Microsoft SQL Server modify the SQL.INI file in the section [win32client.dll] by setting the comdll keyword
to sqlodb32 and in the section [odbcrtr] by setting the longbuffer keyword to 10000.
For Oracle modify the SQL.INI file in the section [win32client.dll] by setting the comdll keyword to sqlora32,
and in the section [oragtwy] by defining the remotedbname keyword for your database with the correct
connect string information, setting the longbuffer keyword equal to 200000, and setting the fetchrow
keyword to 20.
For more information about configuring connections, see Chapter 2 – Initializing and Testing Your Connection,
Chapter 4 – Connecting to Microsoft SQL Server, and Chapter 5 – Connecting to Oracle.
The following is an example of the SQL.INI keywords you define to connect to SQLBase, Microsoft SQL Server,
and Oracle:
[dbntsrv] dbdir=c:\gupta
servername=server1,sqlapipe dbname=island,sqlapipe
[dbntsrv.dll] comdll=sqlapipe
[win32client] clientname=client1
[odbcrtr] longbuffer=10000
Note: Refer to the sample SQL.INI file supplied with the multi-database application for help in editing your
own SQL.INI file.
125
10. Enter a valid user name.
11. Enter a valid password.
12. Choose the appropriate database server.
13. Click Connect.
The default value displayed for Password is ******, but the actual value of the password is SYSADM.
Once you successfully connect to a server, the application removes the name of that server from the
server selection combo box.
14. When you have connected to all three servers, which you must connect do to run the application
successfully, click Exit.
126
• Apply & Close— Commits all pending changes to each database (assuming autocommit is disabled) and
returns to the main form.
• Discard & Exit—Rolls back all pending changes to each database (assuming autocommit is disabled) and
returns to the main form.
Note: To display the bitmap picture for a given row in the PRODUCT table, click the row header (the
leftmost box) in that row.
127
To set (or change) the isolation level, enter one of RO, RL, CS, or RR in the text field. To find out what these
isolation levels mean for Microsoft SQL Server, see “Isolation Levels” on page 4-5. To find out what these
isolation levels mean for SQLBase, see the SQLBase documentation.
You cannot set an isolation level with Oracle.
Note: The sample application may not exit or close windows properly if you select Close from the Windows
system menu. Select File > Exit from the menu bar instead.
Design Issues
This section describes some of the design issues raised in the development of the sample application.
! Disable autocommit
Set bOracleAC=FALSE
Call SqlSetParameter(hOracle,DBP_AUTOCOMMIT, bOracleAC,‘’)
Set dfDatabase=’’
Else If strServer=COMBO_SQLBASE
Set bSQLBaseConnect=SqlConnect(hSQLBase)
If bSQLBaseConnect
Set strDBSQLBase=dfDatabase
Set nCmbEntries=SalListDelete(cmbServer,nCmbIndex)
Call SalListSetSelect(cmbServer,nCmbEntries - 1)
! Disable autocommit
bSQLBaseAC=FALSE
Call SqlSetParameter(hSQLBase,DBP_AUTOCOMMIT, bSQLBaseAC,’’)
Call SqlSetParameter(hSQLBasePop,DBP_AUTOCOMMIT, bSQLBaseAC,’’)
Set dfDatabase=’’ If nCmbEntries=0
Call SalListClear(cmbServer)
Call SalDisableWindow(pbConnect)
...
Message Actions
On SAM_Create
Set dfDatabase='island'
Set dfUserName='sysadm'
Set dfPassword='sysadm'
...
Setting autocommit
In your SQLWindows application you can either specify transaction boundaries explicitly in your application
code, or you can have the database server process each SQL statement in your application as its own
transaction. To specify transaction boundaries explicitly, you first disable autocommit; you then execute
COMMIT or ROLLBACK statements in your application code at the end of every transaction. To have the
129
database server process each SQL statement as its own transaction, enable autocommit. (For more general
information about autocommit, see “Autocommit” on page 12. For information about autocommit and a
given database server, see the chapter devoted to that server.)
In the multi-database application you can enable or disable autocommit independently for each database.
When you write a multi-database application, you need to know what each of the databases you will connect
to does if you disable autocommit, then either disconnect from that database or end the application without
executing a COMMIT or ROLLBACK statement.
For example, if you connect to SQLBase or Oracle and disable autocommit, the database server commits your
last transaction for you if you either disconnect from the database or end your application without executing
a COMMIT or ROLLBACK statement. Under the same circumstances, however, Microsoft SQL Server rolls the
transaction back.
The application initially disables autocommit for all three databases by calling SqlSetParameter with the two
arguments DBP_AUTOCOMMIT and FALSE. With autocommit disabled, the application can ensure that
operations on the various databases are committed only after all portions of a transaction have been
completed successfully.
The code in the application that disables autocommit on SQLBase is the following (hSQLBase is the SQL
handle for the connection to SQLBase):
Call SqlSetParameter(hSQLBase,DBP_AUTOCOMMIT,FALSE,’’)
Note: The sample application controls transactions separately on each of the databases. It does not
perform distributed transactions.
Locking
Intelligent locking improves both concurrency and consistency. Different databases support different locking
strategies and implement different ways for users to set locks. For example, both SQLBase and Microsoft SQL
Server lock entire pages of data. Oracle, on the other hand, locks individual rows (when you execute a
SELECT...FOR UPDATE statement). However, you cannot choose the kind of lock Oracle places on that row.
Note: To set a particular kind of lock in SQLBase and Microsoft SQL Server, you set a certain isolation level
(see “Isolation Levels”, which follows).
Locking strategies are either pessimistic or optimistic. A pessimistic locking strategy assumes that another
user will attempt to update the same row you might be looking at. If you choose this strategy, the database
server locks the row first before you get to see the data, thus ensuring a high degree of data consistency. An
optimistic locking strategy assumes the opposite: no other user will attempt to update the row you are
130
looking at. If you choose this strategy, the database server does not lock the row, thus ensuring a higher
degree of concurrency.
If you adopt an optimistic locking strategy, you must put checks into your code to verify for yourself that
another user of the database has not updated any of the data that the user of your application is viewing.
Isolation levels
SQLBase and Microsoft SQL Server allow you to set isolation levels. An isolation level defines the degree to
which transactions are prevented from interfering with each other. You set the isolation level in your
SQLWindows application by calling the SAL function SqlSetIsolationLevel.
Most databases support several isolation levels. However, the isolation levels are not defined in the same way
on all the databases. The ANSI/SQL committee has defined a standard set of isolation levels with standard
semantics, but most databases do not implement these isolation levels with precisely those semantics.
Some of the names commonly used by database vendors for isolation levels are: Dirty Read, Uncommitted
Read, Cursor Stability, Repeatable Read, and Serializable. Other names you will see include Browse, Read
Only, Release Locks, and Hold Lock.
Warning: Some databases use the same names as those specified by the ANSI/SQL committee for isolation
levels, but they do not implement the ANSI/SQL semantics for those isolation levels. Do not assume you know
what an isolation level means just from its name. You must read the database vendor documentation to find
out what the behavior is for each of the isolation levels defined by that vendor.
Most relational databases allow users to set isolation levels (either at the statement level, the transaction
level, or both) at run-time. These databases also define a default isolation level, but the default varies from
database to database.
Note: Oracle does not allow your application to set an isolation level. This is because SQLWindows
applications use dynamic SQL, and Oracle does not support the setting of isolation levels with
dynamic SQL
For example, the default isolation level in SQLBase is called Repeatable Read (RR). SQLBase implements this
isolation level by maintaining a read lock on the requested row until the transaction has been committed.
Another example comes from Microsoft SQL Server, where the default isolation level is called Read
Uncommitted. With this isolation level, the database may send a client requesting a row the most recently
changed data in that row even if those changes have not yet been committed.
Even though these isolation levels vary in syntax and semantics for each database, SQLWindows allows for up
to four isolation levels. The semantics of these isolation levels depends on the database your application
connects to. To learn which isolation levels are supported for a given database, see the chapter in this
document devoted to that database.
For example, to set the isolation level on Microsoft SQL Server to SQL_TXN_SERIALIZABLE, make the call:
Call SqlSetIsolationLevel(hMSSQLServer,‘RR’)
The application chooses an initial value for the isolation level to guarantee that the data remain consistent
until the application executes a COMMIT or ROLLBACK statement. With this isolation level other database
users are prevented from changing locked data until the application has completed the transaction.
The application executes all SQL statements as Dynamic SQL statements.
131
Note: Because the Oracle OCI does not support the setting of isolation levels for Dynamic SQL statements,
the application does not set an isolation level with Oracle.
Database-oriented client/server applications fall into two broad categories: transaction-based applications
and decision support applications.
Transaction-based applications generally affect one or more tables. All work related to a single transaction
should be committed only if all the operations in that transaction completed successfully. If the application
detects the violation of an integrity constraint, it might choose to roll back the transaction.
Decision support applications typically do a lot of queries and only occasionally change the database. Because
decision support queries usually take a long time to execute, you normally do not want to acquire any locks
along the way. If you do choose to acquire locks during the query, you normally release those locks as soon as
the query is done.
Transaction-based applications need to support a high degree of both concurrency and consistency among
users because these applications are typically run by many users at the same time. To support a high degree
of concurrency these applications typically select the most permissive isolation levels available. These
isolation levels direct the database either to not lock data (allowing dirty reads) or to release locks very
quickly, such as releasing a lock as soon as a row is read. This isolation level is often called “cursor stability”.
Decision support applications do not require high degrees of concurrency; they can use much more restrictive
locking to maintain more data consistency. However, if you write a decision support application knowing it
will access the same database as a transaction-based application, you should design it to use (at least nearly)
the same isolation level as the transaction-based application to support the high degree of concurrency
needed by the transaction-based application.
One way applications can get both a high degree of concurrency and a high degree of data consistency is to
choose a permissive isolation level (one that releases locks quickly), enable cursor context preservation (CCP),
then commit transactions quickly (either by enabling autocommit or executing the COMMIT statement
frequently).
Note: Generally, if both decision support and transaction-based applications access the same database, the
decision support applications should use an optimistic locking strategy to reduce their impact on the
transaction-based applications.
The sample multi-database application combines elements of both a decision support application and a
transaction-based application. The portion that is like a decision support application processes the COMPANY,
PRODUCT, and EMPLOYEE tables; the portion that is transaction-based handles the creating of invoices and
the accessing of the INVOICE_ITEM, PAYMENT, and PRODUCT tables. Because the application is a hybrid, it
needs a high degree of both consistency and concurrency. This application sets the isolation level to
Repeatable Read and disables autocommit. In your own application you must make appropriate design
decisions (such as choosing an isolation level) that let you strike a suitable balance between concurrency and
data consistency.
132
There are some data type differences among SQLBase, Oracle, and Microsoft SQL Server. You see these kinds
of differences whenever you write a single application that accesses heterogeneous databases. Some data
types are not supported on all the databases your application must access.
For example, the picture column in the PRODUCT table on SQLBase is a LONG column. When the application
moves this data to Oracle, it redefines this column as LONG RAW data because the column contains binary
data.
The application copies table data from SQLBase to Oracle, Microsoft SQL Server, or SQLBase itself by
executing a SELECT from SQLBase, then executing an INSERT statement to place the data into the target
database. The application also creates table indexes on the target database.
When creating tables on one database server to receive data from tables on another database server, you
must specify suitable column type definitions in the CREATE TABLE statement. Because different database
servers do not all support the same set of data types, you must decide which data types to use when you
copy data from one database server to another.
For example, most database servers support a data type called VARCHAR. However, the length bounds for this
data type vary from one database server to another.
Depending on the size of the actual VARCHAR data you are copying, you may have to specify a column type
other than VARCHAR (such as LONG, for example) on the database server to which you are copying the data.
Depending on the databases you are accessing in your own applications, you may want to use a different
technique whenever you need to copy data from one database to another, especially if you are moving large
amounts (megabytes) of data. Read the documentation on the databases your applications access for
information that may help you decide how to perform such an operation efficiently.
In the following excerpt, the application creates the EMPLOYEE table on Microsoft SQL Server and the
INVOICE table on Oracle; it then copies the data from the corresponding SQLBase tables to the target
database using the TransferData internal function.
Popup Menu: &Populate Data
...
Menu Item: Microsoft SQL Server
...
Menu Settings
Enabled when: hMSSQLServer
Checked when:
Menu Actions
Set strSQL = ‘CREATE TABLE ‘|| MDB_EMPLOYEE ||
‘ (EMPLOYEE_ID CHAR (8),’ ||
‘LAST_NAME VARCHAR (30),’ ||
‘FIRST_NAME VARCHAR (30),’ ||
‘MI CHAR (1),’ ||
‘EXTENSION VARCHAR (4),’ ||
‘OFFICE_NO VARCHAR (5),’ ||
‘DEPT_ID CHAR (5),’ ||
‘DATE_HIRED DATETIME,’ ||
‘CURRENT_SALARY FLOAT (8))’
If NOT SqlPrepareAndExecute(hMSSQLServer,strSQL)
Set strMsgPrompt=MSGBOX_MSGPART1 || MDB_EMPLOYEE || MSGBOX_MSGPART2
Set nMsgResult=SalMessageBox(strMsgPrompt,MSGBOX_TITLE,MB_OkCancel)
If nMsgResult=IDCANCEL
Return -1
Else
Call TransferData(MDB_EMPLOYEE)
Call SalMessageBox('Create Index for ' || MDB_EMPLOYEE,
'Create Index',MB_Ok)
Set strSQL='CREATE UNIQUE INDEX ' || MDB_EMPLOYEE_IDX ||
133
' ON ' || MDB_EMPLOYEE || ' (EMPLOYEE_ID)'
If NOT SqlPrepareAndExecute(hMSSQLServer,strSQL)
Call SalMessageBox('SQL Error Creating Index ' ||
MDB_EMPLOYEE_IDX,'Error!',MB_Ok)
...
If NOT SqlPrepareAndExecute(hOracle,strSQL)
Set strMsgPrompt = MSGBOX_MSGPART1 || MDB_INVOICE || MSGBOX_MSGPART2
Set nMsgResult=SalMessageBox(strMsgPrompt,MSGBOX_TITLE, MB_OkCancel)
If nMsgResult=IDCANCEL Return -1
Else
Call TransferData(MDB_INVOICE)
Call SalMessageBox('Create Index for ' || MDB_INVOICE,
'Create Index',MB_Ok)
Set strSQL='CREATE INDEX ' || MDB_INVOICE_IDX ||
' ON ' || MDB_INVOICE || ' (INVOICE_NO)'
If NOT SqlPrepareAndExecute (hOracle,strSQL)
Call SalMessageBox ('SQL Error Creating Index ' ||
MDB_INVOICE_IDX,'Error!',MB_Ok)
...
The TransferData function accepts the table name as input, then transfers data from SQLBase to the target
database. If the input table name is MDB_COMPANY, the target database is SQLBase. If MDB_EMPLOYEE or
MDB_PAYMENT, the target database is Microsoft SQL Server. Otherwise, the target database is Oracle.
Function: TransferData
Returns
Boolean: bOk
Parameters
String: strTableName
...
Actions
When SqlError
Call SalMessageBox ('SQL Error in Transfer Data function',
'Transfer Data Error!',MB_Ok)
Return FALSE
If strTableName=MDB_EMPLOYEE
! Read from SQLBase employee table into MS SQL Server
Set strTempSQL=’INSERT INTO ‘|| MDB_EMPLOYEE ||
' VALUES (:dfCol1,:dfCol2,:dfCol3,:dfCol4,:dfCol5,
:dfCol6,:dfCol7,:dfCol8,:dfCol9)'
Call SqlPrepare(hMSSQLServer,strTempSQL)
Set strSQL='SELECT * FROM EMPLOYEE INTO ‘ ||
‘:dfCol1,:dfCol2,:dfCol3,:dfCol4,:dfCol5,’ ||
‘:dfCol6,:dfCol7,:dfCol8,:dfCol9’
134
If SqlPrepareAndExecute(hSQLBasePop,strSQL)
Loop TData1
If SqlFetchNext(hSQLBasePop,nRetval)
Call SqlExecute(hMSSQLServer)
Else
Break TData1
135
In the following code excerpt, the application retrieves data from the EMPLOYEE table (in Microsoft SQL
Server) into a dynamic table window.
Menu Item: &Employee
...
Menu Settings
Enabled when: hMSSQLServer
Checked when:
Menu Actions
Call SalShowWindow(tblInfo)
Call SalBringWindowToTop(tblInfo)
...
Set strSQL=’SELECT * FROM ‘|| MDB_EMPLOYEE
Call SalTblPopulate(tblInfo,hMSSQLServer,strSQL, TBL_FillNormal)
In the following code excerpt, the application retrieves data from the PRODUCT table (in Oracle) into a
dynamic table window.
Menu Item: &ProductInvoice
...
Menu Settings
Enabled when: hOracle
Checked when:
Menu Actions
Call SalShowWindow(tblInfo)
Call SalBringWindowToTop(tblInfo)
Call SalShowWindow(picPicture)
...
Set strSQL='SELECT STYLE_ID,STYLE,DESCRIPTION,PRICE FROM ' || MDB_PRODUCT
Call SalTblPopulate(tblInfo,hOracle,strSQL,TBL_FillNormal)
...
Key Columns
The key columns for the tables used in the multi-database application are the following:
• company_id in the COMPANY table
• employee_id in the EMPLOYEE table
• invoice_no in the INVOICE table
• style_id in the PRODUCT table
You cannot update a key column.
Transaction Processing
The multi-database Team Developer application centers around four transactions.
Three of these transactions involve just a single SQL table located on a specific database server. None of these
tables has dependencies on any other table.
The three transactions are the following:
• Retrieve, insert, delete, and update the COMPANY table on SQLBase.
• Retrieve, insert, delete, and update the PRODUCT table on Oracle.
• Retrieve, insert, delete, and update the EMPLOYEE table on Microsoft SQL Server.
136
The more complex transaction is the INVOICE transaction. It involves multiple tables: the INVOICE and
INVOICE_ITEM tables on Oracle and the PAYMENT table on Microsoft SQL Server. When the user clicks the
Details button for a specified invoice (and the user has also selected the Invoice Item radio button), the
application displays a form showing all invoice items, a single payment entry, and a PRODUCT table listing.
The sample application manages two independent transactions: one on Oracle and the other on Microsoft
SQL Server; it does not process this transaction as a distributed transaction between Oracle and Microsoft
SQL Server.
A distributed transaction is one where the transaction is shared by two or more (possibly heterogeneous)
database servers. When a client executes the COMMIT statement, all the servers participating in the
transaction must coordinate to make a collective yet single decision whether to register all the changes in the
transaction or to undo all the changes.
A commit coordinator (sync-point manager) manages this decision-making process. The coordinator knows
about all the participants, issues a prepare for commit, and receives acknowledgments. When the
coordinator receives all the acknowledgments, it issues a commit to all participants. Once the participants
have all acknowledged a successful commit, the coordinator writes a commit marker. The commit coordinator
also keeps track if a database server goes down during the second portion of the commit phase. If that
happens, the coordinator helps to resolve the transaction.
If a user adds a new invoice item for a selected invoice number, the style_id and item_price columns in the
INVOICE_ITEM table are set from the chosen product selected from the PRODUCT table. Once a quantity is
specified, the amount column in the PAYMENT table is adjusted to reflect the new product quantity and price
by summing all invoice item quantities times their unit price for the specified invoice number.
If the user removes an invoice item for a selected invoice number, the amount column in the PAYMENT table
is adjusted to reflect the removal of a product quantity and price by summing all invoice item quantities times
their unit price for the specified invoice number.
If the user changes the quantity associated with a selected invoice item, the amount column in the PAYMENT
table is adjusted to reflect the modifying of a product quantity and price by summing all invoice item
quantities times their unit price for the specified invoice number.
Note: One useful way to enhance the sample application is to make sure that another application cannot
change a row that the sample application has read until it executes a COMMIT or ROLLBACK. You can
do this on Oracle by retrieving data with the SELECT...FOR UPDATE statement.
The application locks the PAYMENT data because it uses an isolation level of Repeatable Read on Microsoft
SQL Server.
Since the sample application is predominantly transaction-based, we disable autocommit; this lets the
application take control of the transaction boundaries. When the user creates or updates an invoice item, the
application needs to guarantee that all changes are committed only when changes have been successfully
made to all tables. If even one of the updates fails, the application rolls back all the changes that make up the
transaction.
The application must also guarantee the integrity of each row in the tables affected by the transaction. No
client should be allowed to update a row that another client has either read or updated. To do this the
application selects the isolation level Repeatable Read. This puts a lock on every row a user fetches and
maintains that lock until the user commits (or rolls back) the transaction—other users cannot write to any of
the locked rows.
For example, when a user creates a new invoice item, the PAYMENT row needs to be locked while the
application updates the amount column, summing all invoice item quantities and their unit prices. The
137
PRODUCT table row for this invoice item needs to locked so that information cannot be changed and that
PRODUCT entry itself cannot be removed. All other invoice items for the selected invoice number need to be
locked since the application uses those quantities and unit prices to calculate a new amount in the PAYMENT
table. Also, none of the invoice items should be removed while the application does the calculation.
To manage transactions explicitly an application must disable autocommit.
If you disable autocommit and fail to commit or roll back the last transaction before disconnecting or ending
the application, some databases commit the last transaction while others roll it back. Read your database
vendor documentation to find out what your database does in that situation.
Dynamic Binding
Dynamic binding in SQLBase and any database you access using ODBC allows you to use column variables of
type STRING as bind variables. Because you cannot use dynamic binding with Oracle, you must define each
column variable with the correct data type.
In the following code excerpt, the application uses automatic column variables as bind variables to update the
COMPANY table on SQLBase and the EMPLOYEE table on Microsoft SQL Server.
Pushbutton: pbUpdate
...
Message Actions
On SAM_Click
Set nNumCols=SalSendMsg(tblInfo, SAM_GETCOLCOUNT, 0, 0)
Set strSQL='UPDATE '
If nTableIndicator=SQLBASE_TABLE
Set strSQL=strSQL || MDB_COMPANY || ' SET '
Set hLocalSql=hSQLBase
Else If nTableIndicator = MSSQLSERVER_TABLE
Set strSQL=strSQL || MDB_EMPLOYEE || ' SET '
Set hLocalSql=hMSSQLServer
Set nIndex = 2
Loop Binding2
Call SalTblGetColumnTitle(
SalTblGetColumnWindow(tblInfo,nIndex,COL_GetPos),
strColName,MAXCOLNAME_LENGTH)
If nIndex < nNumCols
Set strSQL=strSQL || strColName || ‘= :’ ||
‘tblInfo#’ || SalNumberToStrX (nIndex,0) || ‘, ‘
138
Else If nIndex = nNumCols
Set strSQL=strSQL || strColName || ‘= :’ ||
‘tblInfo#’ || SalNumberToStrX(nIndex,0)
Break Binding2
Set nIndex=nIndex + 1
Call SalTblGetColumnTitle(
SalTblGetColumnWindow(tblInfo,1,COL_GetPos),
strColName,MAXCOLNAME_LENGTH)
Set strSQL=strSQL || ‘ WHERE ‘ || strColName ||
‘ = :tblInfo#1’
Call SqlPrepare(hLocalSql,strSQL)
Call SalTblDoUpdates(tblInfo,hLocalSql,TRUE)
...
The following is an example of similar code required to update the INVOICE table on Oracle where we cannot
take advantage of STRING automatic column variables as bind variables:
Pushbutton: pbUpdate
...
Message Actions
On SAM_Click
Set strSQL='UPDATE '
If nTableIndicator=ORACLE_TABLE1
Set strSQL=strSQL || MDB_INVOICE || ' SET '
Set hLocalSql=hOracle
Set strSQL = strSQL ||
‘COMPANY_ID=:nCompId,’ ||
‘COMPANY_NAME=:strCompName,’ ||
‘INVOICE_DATE=:dInvDate,’ ||
‘DATE_PAID=:dDatePaid,’ ||
‘STATUS=:strStatus,’ ||
‘AMOUNT_PAID=:nAmtPaid,’ ||
‘EMPLOYEE_ID=:strEmpId ‘ ||
‘WHERE INVOICE_NO=:nInvNum’
Set nInvNum=SalStrToNumber(tblInfo#1)
Set nCompId=SalStrToNumber(tblInfo#2)
Set strCompName=tblInfo#3
Set dInvDate=SalStrToDate(tblInfo#4)
Set dDatePaid=SalStrToDate(tblInfo#5)
Set strStatus=tblInfo#6
Set nAmtPaid=SalStrToNumber(tblInfo#7
Set strEmpId=tblInfo#8
Call SqlPrepare(hLocalSql,strSQL)
Call SalTblDoUpdates(tblInfo,hLocalSql,TRUE)
...
Dynamic binding only works if the statement string is in single quotes, example: ‘Hello’ or a string variable is
defined.
The sample application assumes the first column is the key field.
Implementation Details
This section describes some of the implementation details involved in updating table data, dynamic table
windows management, dynamic data type binding, isolation levels, and autocommit.
139
Updating Table Data
The sample application assumes that the first column of a table is a key column; the application uses this key
for update or delete operations. This assumption allows the application to make use of common code when
building the WHERE clause of a SELECT, UPDATE, or DELETE statement.
The following is an example of how the application builds the WHERE clause of a SELECT statement:
Call SalTblGetColumnTitle(
SalTblGetColumnWindow (tblInfo,1,COL_GetPos),
strColName,MAXCOLNAME_LENGTH)
Set strSQL=strSQL || ' WHERE ' || strColName ||
' = :' || 'tblInfo#1'
Oracle
The PICTURE column from the PRODUCT table is not displayed as a column in the dynamic table window
because the data is a bit map. There is a separate area on the form where the product image is displayed if
the user clicks on the row header of a given PRODUCT table entry.
If the user selects the Table menu option, the application calls SalTblPopulate to build a dynamic table
window for the INVOICE and PRODUCT tables on Oracle.
140
Dynamic Data Type Binding
Because Oracle does not support dynamic data type binding, the application does not use the automatic
column variables as bind variables for data types other than STRING in the INSERT, UPDATE, or DELETE
statements. For the NUMBER and DATE data types, the application calls SalStrToNumber and SalStrToDate to
convert the automatic variable string data to the correct number or date format—the application uses a
specific bind variable of that data type.
Oracle
For the Populate menu option, the TransferData function fetches row data from SQLBase into specific data
type column variables (for example, nCompId of type NUMBER, dDatePaid of type DATE/TIME, and so forth).
When the application inserts a row of data into the Oracle database, it uses these data-type-specific variables
as the program variables.
When the user clicks the Insert, Update, Delete, or Refresh buttons, the application calls an appropriate SAL
function to convert the data associated with each dynamic column variable created by SalTblPopulate into a
NUMBER or DATE/TIME specific column variable. The application uses these data-type-specific column
variables as bind variable names on the associated INSERT, UPDATE, DELETE, or SELECT statement.
To copy data from SQLBase to Oracle, the application must map the SQLBase column data types to the Oracle
data types. Because SAL has no functions for obtaining the data type of each column in a table, the
application must hard-code the appropriate values of the CREATE TABLE statement that it executes on the
target database (the one to which it copies the data). For example, the picture column is a bit map stored on
SQLBase in a LONG column. To store this data on Oracle, the application must use a LONG RAW column.
141
Autocommit
The sample application turns off autocommit for SQLBase, Microsoft SQL Server, and Oracle. The application
is responsible for committing (or rolling back) the operations that make up a transaction.
You may find it instructive to modify the sample application by enabling autocommit and observe how the
application runs differently.
While the application does manage its own transactions, it does not manage the operations on both Oracle
and Microsoft SQL Server as a single distributed transaction. Instead, the application commits changes to
INVOICE and INVOICE_ITEM tables (on Oracle) separately from the PAYMENT table (on Microsoft SQL Server).
For example, if the commit fails for the PAYMENT table, the application rolls back not only the changes in the
PAYMENT table on Microsoft SQL Server, but also the changes in the INVOICE and INVOICE_ITEM tables on
Oracle. If the commit succeeds for the PAYMENT table, the application commits the changes to the INVOICE
and INVOICE_ITEM tables on Oracle also. If the commit for those tables fails, you can roll back the changes in
those tables, but at this point you cannot go back to Microsoft SQL Server and roll back the PAYMENT table
changes already committed.
This code excerpt shows how the application coordinates commit (and rollback, if required) between
Microsoft SQL Server and Oracle:
On SAM_Click
If NOT bOracleAC
If NOT SqlCommit(hOracle)
If SqlPrepareAndExecute(hOracle,'rollback')
Call SalMessageBox(‘Oracle changes were successfully’ ||
‘ rolled back’,’Rollback Status’,MB_Ok)
Return -1
Else
Call SalMessageBox( 'Oracle changes were successfully’ || ‘
committed’,’Commit Status’,MB_Ok)
Important: If you successfully commit on Microsoft SQL Server, try to commit on Oracle. If the commit on
Oracle fails, you can do a rollback there, but you cannot roll back the changes you committed on Microsoft
SQL Server.
142
Getting More Information
For more information about transactions, you can read Transaction Processing: Concepts and Techniques by
Jim Gray and Andreas Reuter. You might also want to find out if your database servers can handle distributed
transactions using industry standard protocols such as X/Open XA+. If they do, you might want to adopt those
protocols using the External Call Functions feature of SQLWindows.
143
Glossary
bind variable—A variable that associates data to an SQL statement at runtime. You can use bind variables in
the VALUES clause of an INSERT statement, in a WHERE clause, or in the SET clause of an UPDATE statement.
commit—The act of making permanent pending changes against a database.
cursor—A work space in memory that is used for processing an SQL statement. This work space contains the
return code, number of rows, error position, number of select list items, number of program variables,
rollback flag, and the command result. A cursor is part of a SQL handle. Alternatively, a pointer to a row in a
result set.
DCC—Database Connectivity Configuration.
DDL—SQL statements that define and alter database structures, such as tables, views, and indexes. Example
statements are CREATE TABLE and DROP INDEX.
DML—SQL statements that add, delete, change, or retrieve data from the database, such as INSERT, DELETE,
UPDATE, or SELECT.
Data Definition Language—see DDL.
Data Manipulation Language—see DML.
dirty read—A read of a value that was never committed to the database. For example, transaction A changes
one or more column values in a row. Transaction B reads the same row, after which transaction A rolls back its
changes. Transaction B has now performed a dirty read, because it read values that (from a transaction-
oriented point of view) never existed.
nonrepeatable read—The reading of data from a given row such that the values read are not guaranteed to
be always the same. For example, transaction A reads a row, then transaction B either updates or deletes the
row. Transaction A cannot now repeat the read of that row and get the same results; either the values are
different or the row no longer exists.
phantom row—A row that appears in between two executions of the same SELECT statement. For example,
transaction A performs a SELECT on a table. Based on the selection criteria in the SELECT statement, the
database server returns a set of rows to A. Transaction B inserts one or more new rows into the same table
with values that happen to match the selection criteria of the SELECT statement used by A. If transaction A re-
executes the same SELECT statement, it obtains a different set of rows than it did the first time; the new rows
are phantom rows.
rollback—The act of undoing pending changes against a database.
SAL—See Scalable Application Language.
Scalable Application Language—An object-oriented language for writing SQLWindows/32 applications.
SQL handle—A program variable that identifies a connection context to a database. Multiple SQL handles can
share the same connection to a database. It is often true that an action performed on any one of those
handles actually affects all the handles sharing the same connection. See also cursor.
SQLRouter—A software library that maps between the actions and data types of a SQLWindows/32
application and the actions and data types of a target database or data source.
transaction—A logical unit of work whose elements (changes either to database data or to database data
structures) can be potentially applied to a database. The elements of a transaction are either all applied to
the database or else all discarded; the elements of a transaction constitute an indivisible unit.
144
145