Adaptive Server Anywhere User’s Guide

Last modified: November 2000 Part Number: MC0057

Copyright © 2001 Sybase, Inc. All rights reserved. Information in this manual may change without notice and does not represent a commitment on the part of Sybase, Inc. and its subsidiaries. Sybase, Inc. provides the software described in this manual under a Sybase License Agreement. The software may be used only in accordance with the terms of the agreement. No part of this publication may be reproduced, transmitted, or translated in any form or by any means, electronic, mechanical, manual, optical, or otherwise, without the prior written permission of Sybase, Inc. Sybase, SYBASE (logo), ADA Workbench, Adaptable Windowing Environment, Adaptive Component Architecture, Adaptive Server, Adaptive Server Anywhere, Adaptive Server Enterprise, Adaptive Server Enterprise Monitor, Adaptive Server Enterprise Replication, Adaptive Server Everywhere, Adaptive Server IQ, Adaptive Warehouse, AnswerBase, Anywhere Studio, Application Manager, AppModeler, APT-Build, APT-Edit, APT-Execute, APT-FORMS, APT-Library, APT-Translator, APT Workbench, ASEP, Backup Server, BayCam, Bit-Wise, Certified PowerBuilder Developer, Certified SYBASE Professional, Certified SYBASE Professional (logo), ClearConnect, Client Services, Client-Library, CodeBank, Cohesion, Column Design, ComponentPack, Connection Manager, CSP, Data Pipeline, Data Workbench, DataArchitect, Database Analyzer, DataExpress, DataServer, DataWindow, DB-Library, dbQueue, Developers Workbench, Direct Connect Anywhere, DirectConnect, Distribution Director, Dynamo, E-Anywhere, E-Whatever, Electronic Case Management, Embedded SQL, EMS, Enterprise Application Server, Enterprise Application Studio, Enterprise Client/Server, Enterprise Connect, Enterprise Data Studio, Enterprise Manager, Enterprise SQL Server Manager, Enterprise Work Architecture, Enterprise Work Designer, Enterprise Work Modeler, EWA, Financial Fusion, First Impression, Formula One, Gateway Manager, GeoPoint, ImpactNow, InfoMaker, Information Anywhere, Information Everywhere, InformationConnect, InstaHelp, Intellidex, InternetBuilder, iScript, Jaguar CTS, jConnect for JDBC, KnowledgeBase, Logical Memory Manager, MainframeConnect, Maintenance Express, MAP, MDI Access Server, MDI Database Gateway, media.splash, MetaWorks, MethodSet, MobiCATS, MySupport, Net-Gateway, Net-Library, NetImpact, Next Generation Learning, Next Generation Learning Studio, O DEVICE, OASiS, OASiS (logo), ObjectConnect, ObjectCycle, OmniConnect, OmniSQL Access Module, OmniSQL Toolkit, Open Client, Open Client/Server, Open Client/Server Interfaces, Open ClientConnect, Open Gateway, Open Server, Open ServerConnect, Open Solutions, Optima++, Partnerships that Work, PB-Gen, PC APT Execute, PC DB-Net, PC Net Library, PhysicalArchitect, Power Through Knowledge, Power++, power.stop, PowerAMC, PowerBuilder, PowerBuilder Foundation Class Library, PowerDesigner, PowerDimensions, PowerDynamo, PowerJ, PowerScript, PowerSite, PowerSocket, Powersoft, Powersoft Portfolio, Powersoft Professional, PowerStage, PowerStudio, PowerTips, PowerWare Desktop, PowerWare Enterprise, ProcessAnalyst, Relational Beans, Replication Agent, Replication Driver, Replication Server, Replication Server Manager, Replication Toolkit, Report Workbench, Report-Execute, Resource Manager, RW-DisplayLib, RW-Library, S-Designor, S Designor, SAFE, SAFE/PRO, SDF, Secure SQL Server, Secure SQL Toolset, Security Guardian, SKILS, smart.partners, smart.parts, smart.script, SQL Advantage, SQL Anywhere, SQL Anywhere Studio, SQL Code Checker, SQL Debug, SQL Edit, SQL Edit/TPU, SQL Everywhere, SQL Modeler, SQL Remote, SQL Server, SQL Server Manager, SQL Server SNMP SubAgent, SQL Server/CFT, SQL Server/DBM, SQL SMART, SQL Station, SQL Toolset, SQLJ, Startup.Com, STEP, SupportNow, Sybase Central, Sybase Client/Server Interfaces, Sybase Development Framework, Sybase Financial Server, Sybase Gateways, Sybase Learning Connection, Sybase SQL Desktop, Sybase SQL Lifecycle, Sybase SQL Workgroup, Sybase Synergy Program, Sybase User Workbench, Sybase Virtual Server Architecture, Sybase MPP, SybaseWare, Syber Financial, SyberAssist, SyBooks, System XI (logo), System 10, System 11, SystemTools, Tabular Data Stream, The Enterprise Client/Server Company, The Extensible Software Platform, The Future Is Wide Open, The Learning Connection, The Model For Client/Server Solutions, The Online Information Center, Transact-SQL, Translation Toolkit, Turning Imagination Into Reality, UltraLite, UNIBOM, Unilib, Uninull, Unisep, Unistring, URK Runtime Kit for UniCode, Viewer, Visual Components, VisualSpeller, VisualWriter, VQL, Warehouse Control Center, Warehouse Studio, Warehouse WORKS, WarehouseArchitect, Watcom, Watcom SQL Server, Watcom SQL, Web.PB, Web.SQL, Web Deployment Kit, WebSights, WebViewer, WorkGroup SQL Server, XA-Library, XA-Server, and XP Server are trademarks of Sybase, Inc. or its subsidiaries. All other trademarks are property of their respective owners. Last modified: March 2000. Part Number: MC0057.

Contents

About This Manual.......................................................... xiii
Related documentation ...........................................................xiv Documentation conventions.................................................... xv The sample database............................................................ xviii

PART ONE Starting and Connecting to Your Database ..................... 1 1 Running the Database Server ........................................... 3
Introduction ............................................................................... 4 Starting the server..................................................................... 7 Some common command-line switches ................................... 9 Stopping the database server ................................................. 15 Starting and stopping databases ............................................ 17 Running the server outside the current session ..................... 18 Troubleshooting server startup ............................................... 30

2

Connecting to a Database............................................... 33
Introduction to connections ..................................................... 34 Connecting from Sybase Central or Interactive SQL ......................................................................................... 38 Simple connection examples .................................................. 41 Working with ODBC data sources .......................................... 49 Connecting from desktop applications to a Windows CE database............................................................ 59 Connecting to a database using OLE DB ............................... 62 Connection parameters........................................................... 64 Troubleshooting connections .................................................. 67 Using integrated logins ........................................................... 77

3

Client/Server Communications....................................... 85
Network communication concepts .......................................... 86 Real world protocol stacks ...................................................... 91 Supported network protocols .................................................. 94 iii

Using the TCP/IP protocol ...................................................... 95 Using the SPX protocol........................................................... 98 Using the NetBIOS protocol.................................................. 100 Using Named Pipes .............................................................. 101 Troubleshooting network communications ........................... 102

PART TWO Working with Databases ............................................... 109 4 Working with Database Objects ................................... 111
Introduction ........................................................................... 112 Working with databases........................................................ 115 Working with tables............................................................... 124 Working with views ............................................................... 138 Working with indexes ............................................................ 145

5

Queries: Selecting Data from a Table .......................... 149
Query overview ..................................................................... 150 The SELECT clause: specifying columns............................. 153 The FROM clause: specifying tables .................................... 161 The WHERE clause: specifying rows ................................... 162

6

Summarizing, Grouping, and Sorting Query Results.. 173
Summarizing query results using aggregate functions................................................................................ 174 The GROUP BY clause: organizing query results into groups ............................................................................ 178 Understanding GROUP BY................................................... 180 The HAVING clause: selecting groups of data ..................... 184 The ORDER BY clause: sorting query results ...................... 187 The UNION operation: combining queries............................ 190 Standards and compatibility.................................................. 192

7

Joins: Retrieving Data from Several Tables ................ 195
How joins work ...................................................................... 196 How joins are structured ....................................................... 198 Key joins................................................................................ 200 Natural joins .......................................................................... 202 Joins using comparisons....................................................... 203 Inner, left-outer, and right-outer joins.................................... 205 Self-joins and correlation names .......................................... 209 Cross joins ............................................................................ 211

iv

How joins are processed....................................................... 214 Joining more than two tables ................................................ 216 Joins involving derived tables ............................................... 219 Transact-SQL outer joins ...................................................... 220

8

Using Subqueries .......................................................... 223
What is a subquery? ............................................................. 224 Using Subqueries in the WHERE clause .............................. 225 Subqueries in the HAVING clause........................................ 226 Subquery comparison test .................................................... 228 Quantified comparison tests with ANY and ALL ................... 230 Testing set membership with IN conditions .......................... 233 Existence test........................................................................ 235 Outer references ................................................................... 237 Subqueries and joins ............................................................ 238 Nested subqueries ................................................................ 241 How subqueries work............................................................ 243

9

Adding, Changing, and Deleting Data .......................... 253
Data modification statements................................................ 254 Adding data using INSERT ................................................... 255 Changing data using UPDATE ............................................. 259 Deleting data using DELETE ................................................ 261

10

Using SQL in Applications ............................................ 263
Executing SQL statements in applications ........................... 264 Preparing statements ............................................................ 266 Introduction to cursors .......................................................... 269 Types of cursor ..................................................................... 272 Working with cursors............................................................. 275 Describing result sets............................................................ 281 Controlling transactions in applications ................................ 283

11

International Languages and Character Sets .............. 287
Introduction to international languages and character sets........................................................................ 288 Understanding character sets in software ............................ 291 Understanding locales .......................................................... 297 Understanding collations....................................................... 303 Understanding character set translation ............................... 311 Collation internals.................................................................. 314 International language and character set tasks .................... 319

v

PART THREE Relational Database Concepts ..................................... 331 12 Designing Your Database ............................................. 333
Introduction ........................................................................... 334 Database design concepts.................................................... 335 The design process............................................................... 341 Designing the database table properties .............................. 355

13

Ensuring Data Integrity ................................................. 357
Data integrity overview.......................................................... 358 Using column defaults........................................................... 362 Using table and column constraints ...................................... 367 Using domains ...................................................................... 371 Enforcing entity and referential integrity ............................... 374 Integrity rules in the system tables ....................................... 379

14

Using Transactions and Isolation Levels..................... 381
Introduction to transactions................................................... 382 Isolation levels and consistency............................................ 386 Transaction blocking and deadlock ...................................... 392 Choosing isolation levels ...................................................... 394 Isolation level tutorials........................................................... 398 How locking works ................................................................ 413 Particular concurrency issues ............................................... 426 Replication and concurrency................................................. 428 Summary............................................................................... 430

PART FOUR Adding Logic to the Database ...................................... 433 15 Using Procedures, Triggers, and Batches................... 435
Procedure and trigger overview............................................ 437 Benefits of procedures and triggers...................................... 438 Introduction to procedures .................................................... 439 Introduction to user-defined functions................................... 446 Introduction to triggers .......................................................... 450 Introduction to batches.......................................................... 457 Control statements................................................................ 459 The structure of procedures and triggers.............................. 462 Returning results from procedures ....................................... 466 Using cursors in procedures and triggers ............................. 471 vi

Errors and warnings in procedures and triggers................... 474 Using the EXECUTE IMMEDIATE statement in procedures ............................................................................ 483 Transactions and savepoints in procedures and triggers .................................................................................. 484 Some tips for writing procedures .......................................... 485 Statements allowed in batches ............................................. 487 Calling external libraries from procedures ............................ 488

16

Automating Tasks Using Schedules and Events ........ 495
Introduction ........................................................................... 496 Understanding schedules ..................................................... 498 Understanding events ........................................................... 500 Understanding event handlers .............................................. 504 Schedule and event internals................................................ 506 Scheduling and event handling tasks ................................... 508

17

Welcome to Java in the Database................................. 513
Introduction to Java in the database ..................................... 514 Java in the database Q & A .................................................. 517 A Java seminar ..................................................................... 523 The runtime environment for Java in the database ............................................................................... 533 A Java in the database exercise ........................................... 541

18

Using Java in the Database........................................... 549
Overview of using Java......................................................... 550 Java-enabling a database..................................................... 553 Installing Java classes into a database................................. 558 Creating columns to hold Java objects ................................. 563 Inserting, updating, and deleting Java objects...................... 565 Querying Java objects .......................................................... 570 Comparing Java fields and objects ....................................... 572 Special features of Java classes in the database................. 575 How Java objects are stored................................................. 580 Java database design ........................................................... 583 Using computed columns with Java classes ........................ 586 Configuring memory for Java................................................ 589

19

Data Access Using JDBC .............................................. 591
JDBC overview...................................................................... 592 Establishing JDBC connections ............................................ 597

vii

Using JDBC to access data .................................................. 604 Using the Sybase jConnect JDBC driver .............................. 612 Creating distributed applications........................................... 616

20

Debugging Logic in the Database ................................ 621
Introduction to debugging in the database............................ 622 Tutorial 1: Connecting to a database.................................... 624 Tutorial 2: Debugging a stored procedure ............................ 627 Tutorial 3: Debugging a Java class....................................... 630 Common debugger tasks...................................................... 635 Writing debugger scripts ....................................................... 637

PART FIVE Database Administration and Advanced Use .............. 643 21 Backup and Data Recovery........................................... 645
Introduction to backup and recovery..................................... 646 Understanding backups ........................................................ 651 Designing backup procedures .............................................. 654 Configuring your database for data protection...................... 663 Backup and recovery internals.............................................. 667 Backup and recovery tasks................................................... 674

22

Importing and Exporting Data ...................................... 693
Introduction to import and export .......................................... 694 Understanding importing and exporting................................ 696 Designing import procedures ................................................ 701 Designing export procedures ................................................ 705 Designing rebuild and extract procedures ............................ 709 Import and export internals ................................................... 713 Import tasks .......................................................................... 715 Export tasks .......................................................................... 721 Rebuild tasks ........................................................................ 729 Extract Tasks ........................................................................ 734

23

Managing User IDs and Permissions ........................... 735
Database permissions overview ........................................... 736 Setting user and group options ............................................. 740 Managing individual user IDs and permissions .................... 741 Managing connected users................................................... 752 Managing groups .................................................................. 753 Database object names and prefixes ................................... 760

viii

Using views and procedures for extra security ..................... 762 Changing Ownership on Nested Objects.............................. 765 How user permissions are assessed .................................... 767 Managing the resources connections use ............................ 768 Users and permissions in the system tables ........................ 769

24

Keeping Your Data Secure ............................................ 771
Security features overview.................................................... 772 Security tips........................................................................... 773 Controlling database access................................................. 775 Controlling the tasks users can perform ............................... 777 Auditing database activity ..................................................... 778 Running the database server in a secure fashion ................ 782

25

Working with Database Files ........................................ 785
Overview of database files.................................................... 786 Using additional dbspaces .................................................... 788 Working with write files ......................................................... 792 Using the utility database...................................................... 794

26

Monitoring and Improving Performance ...................... 799
Top performance tips ............................................................ 800 Using the cache to improve performance ............................. 807 Using keys to improve query performance ........................... 811 Using indexes to improve query performance ...................... 816 Search strategies for queries from more than one table ...................................................................................... 820 Sorting query results ............................................................. 823 Temporary tables used in query processing......................... 824 How the optimizer works....................................................... 826 Monitoring database performance ........................................ 829

27

Query Optimization........................................................ 835
The role of the optimizer ....................................................... 836 Steps in optimization ............................................................. 838 Reading access plans ........................................................... 839 Underlying assumptions........................................................ 841 Physical data organization and access................................. 845 Indexes.................................................................................. 848 Predicate analysis ................................................................. 850 Semantic query transformations ........................................... 852 Selectivity estimation............................................................. 856

ix

Join enumeration and index selection .................................. 862 Cost estimation ..................................................................... 864 Subquery caching ................................................................. 865

28

Deploying Databases and Applications ....................... 867
Deployment overview............................................................ 868 Understanding installation directories and file names ................................................................................... 870 Using InstallShield templates for deployment....................... 873 Using a silent installation for deployment ............................. 875 Deploying client applications................................................. 878 Deploying database servers ................................................. 887 Deploying embedded database applications ........................ 889

29

Accessing Remote Data................................................ 893
Introduction ........................................................................... 894 Basic concepts ...................................................................... 896 Working with remote servers ................................................ 898 Working with external logins ................................................. 903 Working with proxy tables ..................................................... 905 Example: a join between two remote tables ......................... 910 Accessing multiple local databases ...................................... 912 Sending native statements to remote servers ...................... 913 Using remote procedure calls (RPCs) .................................. 914 Transaction management and remote data.......................... 917 Internal operations ................................................................ 919 Troubleshooting remote data access.................................... 923

30

Server Classes for Remote Data Access ..................... 925
Overview ............................................................................... 926 JDBC-based server classes.................................................. 927 ODBC-based server classes................................................. 930

31

Three-tier Computing and Distributed Transactions .. 943
Introduction ........................................................................... 944 Three-tier computing architecture ......................................... 945 Using distributed transactions............................................... 949 Using Enterprise Application Server with Adaptive Server Anywhere .................................................................. 951

x

PART SIX The Adaptive Server Family .......................................... 955 32 Transact-SQL Compatibility.......................................... 957
An overview of Transact-SQL support .................................. 958 Adaptive Server architectures............................................... 961 Configuring databases for Transact-SQL compatibility .......................................................................... 967 Writing compatible SQL statements...................................... 975 Transact-SQL procedure language overview ....................... 980 Automatic translation of stored procedures .......................... 983 Returning result sets from Transact-SQL procedures ............................................................................ 984 Variables in Transact-SQL procedures................................. 985 Error handling in Transact-SQL procedures ......................... 986

33

Adaptive Server Anywhere as an Open Server............ 989
Open Clients, Open Servers, and TDS................................. 990 Setting up Adaptive Server Anywhere as an Open Server.......................................................................... 992 Configuring Open Servers .................................................... 994 Characteristics of Open Client and jConnect connections ......................................................................... 1000

34

Replicating Data with Replication Server................... 1003
Introduction to replication.................................................... 1004 A replication tutorial............................................................. 1007 Configuring databases for Replication Server .................... 1017 Using the LTM..................................................................... 1020

PART SEVEN Appendixes .................................................................. 1031 A Dialog Box Descriptions ............................................. 1033
Introduction to dialog boxes ................................................ 1034 Dialogs accessed through the File menu............................ 1035 Dialogs accessed through the Tools menu......................... 1045 Debugger windows.............................................................. 1053

xi

B

Property Sheet Descriptions........................................1061
Introduction to property sheets ........................................... 1063 Service properties ............................................................... 1064 Server properties ................................................................ 1067 Statistics properties............................................................. 1069 Database properties............................................................ 1070 Table properties .................................................................. 1072 Column properties............................................................... 1075 Foreign Key properties........................................................ 1078 Index properties .................................................................. 1081 Trigger properties................................................................ 1082 View properties ................................................................... 1083 Procedures and Functions properties................................. 1084 Users and Groups properties.............................................. 1085 Integrated Logins properties ............................................... 1088 Java Objects properties ...................................................... 1089 Domains properties............................................................. 1090 Events properties ................................................................ 1091 Publications properties........................................................ 1092 Articles properties ............................................................... 1093 Remote Users properties .................................................... 1095 Message Types properties.................................................. 1099 Connected Users properties ............................................... 1100 Database Space properties ................................................ 1101 Remote Servers properties ................................................. 1102 MobiLink Synchronization Templates properties ................ 1103

Glossary........................................................................1107 Index..............................................................................1125

xii

About This Manual

Subject

This manual describes how to use Adaptive Server Anywhere. It includes material needed to develop applications that work with Adaptive Server Anywhere and material for designing, building, and administering Adaptive Server Anywhere databases. This manual is for all users of Adaptive Server Anywhere. This manual assumes that you have an elementary familiarity with database management systems and Adaptive Server Anywhere in particular. If you do not have such a familiarity, you should consider reading Adaptive Server Anywhere Getting Started before reading this manual.
Online documentation more current

Audience

Before you begin

The printed version of this book may not be updated with each maintenance release of Adaptive Server Anywhere. The online Help version is updated with each maintenance release and so is more current. Contents
Topic Related documentation Documentation conventions The sample database Page xiv xv xviii

xiii

Related documentation
Adaptive Server Anywhere is a part of SQL Anywhere Studio. For an overview of the different components of SQL Anywhere Studio, see Introducing SQL Anywhere Studio. The Adaptive Server Anywhere documentation consists of the following books: ♦
Getting Started

Intended for all users of Adaptive Server Anywhere, this book describes the following: ♦ ♦ ♦ ♦ New features in Adaptive Server Anywhere Behavior changes from previous releases Upgrade procedures Introductory material for beginning users.

Programming Interfaces Guide

Intended for application developers writing programs that directly access the ODBC, Embedded SQL, or Open Client interfaces, this book describes how to develop applications for Adaptive Server Anywhere. This book is not required for users of Application Development tools with built-in ODBC support, such as Sybase PowerBuilder.

Reference A full reference to Adaptive Server Anywhere. This book describes the database server, the administration utilities, the SQL language, and error messages. Quick Reference

♦ ♦

A handy printed booklet with complete SQL syntax and other key reference material in a concise format.

Read Me First (UNIX only) A separate booklet is provided with UNIX versions of Adaptive Server Anywhere, describing installation and adding some UNIX-specific notes.

The format of these books (printed or online) may depend on the product in which you obtained Adaptive Server Anywhere. Depending on which package you have purchased, you may have additional books describing other components of your product.

xiv

Documentation conventions
This section lists the typographic and graphical conventions used in this documentation.

Syntax conventions
The following conventions are used in the SQL syntax descriptions: ♦
Keywords All SQL keywords are shown in UPPER CASE. However, SQL keywords are case insensitive, so you can enter keywords in any case you wish; SELECT is the same as Select which is the same as select. Placeholders

♦ ♦ ♦

Items that must be replaced with appropriate identifiers or expressions are shown in italics.

Continuation Lines beginning with ... are a continuation of the statements from the previous line. Repeating items

Lists of repeating items are shown with an element of the list followed by an ellipsis (three dots). One or more list elements are allowed. If more than one is specified, they must be separated by commas. Optional portions of a statement are enclosed by square brackets. For example,
RELEASE SAVEPOINT [ savepoint-name ]

Optional portions

indicates that the savepoint-name is optional. The square brackets should not be typed. ♦
Options

When none or only one of a list of items must be chosen, the items are separated by vertical bars and the list enclosed in square brackets. For example,
[ ASC | DESC ]

indicates that you can choose one of ASC, DESC, or neither. The square brackets should not be typed. ♦
Alternatives When precisely one of the options must be chosen, the alternatives are enclosed in curly braces. For example, QUOTES { ON | OFF }

indicates that exactly one of ON or OFF must be provided. The braces should not be typed. xv

Graphic icons
The following icons are used in this documentation:
Icon Meaning

A client application.

A database server, such as Sybase Adaptive Server Anywhere or Adaptive Server Enterprise.

An UltraLite application and database server. In UltraLite, the database server and the application are part of the same process.

A database. In some high-level diagrams, the icon may be used to represent both the database and the database server that manages it. Replication or synchronization middleware. These pieces of software assist in sharing data among databases. Examples are the MobiLink synchronization server, the SQL Remote Message Agent, and the Replication Agent for use with Replication Server. A Sybase Replication Server.

API

A programming interface.

xvi

Installed files
The following terms are used throughout the manual: ♦ ♦
Installation directory

The directory into which you install Adaptive

Server Anywhere.
Executable directory The executables and other files for each operating system are held in an executable subdirectory of the installation directory. This subdirectory has the following name:

♦ ♦ ♦

Windows NT and Windows 95/98 UNIX

win32

bin

NetWare and Windows CE The executables are held in the Adaptive Server Anywhere installation directory itself on these platforms.

xvii

The sample database
There is a sample database included with Adaptive Server Anywhere. Many of the examples throughout the documentation use this sample database. The sample database represents a small company. It contains internal information about the company (employees, departments, and financial data) as well as product information (products), sales information (sales orders, customers, and contacts), and financial information (fin_code, fin_data). The following figure shows the tables in the sample database and how they relate to each other.

asademo.db
product
id name description size color quantity unit_price <pk> integer char(15) char(30) char(18) char(6) integer numeric(15,2)

sales_order_items
id line_id id = prod_id prod_id quantity ship_date <pk,fk> <pk> <fk> integer smallint integer integer date

employee
emp_id manager_id emp_fname emp_lname dept_id street city state zip_code phone status ss_number salary start_date termination_date birth_date bene_health_ins bene_life_ins bene_day_care sex <pk> integer integer char(20) char(20) <fk> integer char(40) char(20) char(4) char(9) char(10) char(1) char(11) numeric(20,3) date date date char(1) char(1) char(1) char(1)

id = id

emp_id = sales_rep

customer
id fname lname address city state zip phone company_name <pk> integer char(15) char(20) char(35) char(20) char(2) char(10) char(12) char(35)

sales_order
id cust_id order_date id = cust_id fin_code_id region sales_rep <pk> integer <fk> integer date <fk> char(2) char(7) <fk> integer

code = fin_code_id

fin_code contact
id last_name first_name title street city state zip phone fax <pk> integer char(15) char(15) char(2) char(30) char(20) char(2) char(5) char(10) char(10) code type description <pk> char(2) char(10) char(50) dept_id = dept_id emp_id = dept_head_id

code = code

fin_data
year quarter code amount <pk> <pk> <pk,fk> char(4) char(2) char(2) numeric(9)

department
dept_id dept_name dept_head_id <pk> integer char(40) <fk> integer

xviii

The sample database is held in a file named asademo.db, and is located in your installation directory.

xix

xx

P A R T

O N E

Starting and Connecting to Your Database

This part describes how to start the Adaptive Server Anywhere database server, and how to connect to your database from a client application.

1

2

C H A P T E R

1

Running the Database Server

About this chapter

This chapter describes how to start and stop the Adaptive Server Anywhere database server, and the options open to you on startup under different operating systems.
Topic Introduction Starting the server Some common command-line switches Stopping the database server Starting and stopping databases Running the server outside the current session Troubleshooting server startup Page 4 7 9 15 17 18 30

Contents

3

Introduction

Introduction
Adaptive Server Anywhere provides two versions of the database server: ♦
The personal database server

This executable does not support client/server communications across a network. Although provided for single-user, same-machine usefor example, as an embedded database engineit is also useful for development work.

On Windows 95/98 and Windows NT the name of the personal server executable is dbeng7.exe. On UNIX operating systems is dbeng7. ♦
The network database server

Intended for multi-user use, this executable supports client/server communications across a network.

On Windows 95/98 and Windows NT the name of the network server executable is dbsrv7.exe. On Novell NetWare the name is dbsrv7.nlm, and on UNIX operating systems it is dbsrv7. Server differences The request-processing engine is identical in the two servers. Each supports exactly the same SQL, and exactly the same database features. The main differences include: ♦ ♦
Network protocol support Only the network server supports communications across a network. Number of connections The personal server has a limit of ten simultaneous connections. The limit for the network server depends on your license. Number of CPUs

The personal database server uses a maximum of two CPUs for request processing. The network database server has no set limit.

You can configure the number of requests the server can process at one time using the -gn command-line switch. The network database server has a default of 20 threads and no set limit, while the personal database server has a default and limit of 10 threads.
Default number of internal threads

$ For information on database server command-line switches, see
"The database server" on page 14 of the book ASA Reference. ♦
Startup defaults

To reflect their use as a personal server and a server for many users, the startup defaults are slightly different for each.

4

Chapter 1 Running the Database Server

First steps
You can start a personal server running on a single database very simply. For example, you can start both a personal server and a database called test.db by typing the following command in the directory where test.db is located:
dbeng7 test

Where to enter commands

You can enter commands in several ways, depending on your operating system. For example, you can: ♦ ♦ ♦ ♦ type the command at a system command prompt. place the command in a shortcut or desktop icon. run the command in a batch file. include the command as a StartLine parameter in a connection string.

$ For more information, see "StartLine connection parameter" on
page 63 of the book ASA Reference. There are slight variations in the basic command from platform to platform, described in the following section.

$ You can also start a personal server using a database file name in a
connection string. For more information, see "Connecting to an embedded database" on page 43.

Start the database server
The way you start the database server varies slightly depending on the operating system you use. This section describes how to enter command lines for the simple case of running a single database with default settings, on each supported operating system. Notes ♦ ♦ ♦ These commands start the personal server (dbeng7). To start a network server, simply replace dbeng7 with dbsrv7. If the database file is in the starting directory for the command, you do not need to specify path. If you do not specify a file extension in database-file, the extension .db is assumed.

v To start the database server using default options:

Windows 95/98/NT Open a command prompt, and enter the following

command:
start dbeng7 path\database-file

5

Introduction
If you omit the database file, a window is displayed allowing you to locate a database file from a Browse button. ♦ ♦
UNIX

Open a command prompt, and enter the following command:

dbeng7 path/database-file NetWare

The database server for NetWare is a NetWare Loadable Module (dbsrv7.nlm). An NLM is a program that you can run on your NetWare server. Load a database server on your NetWare server as follows:
load dbsrv7.nlm path\database-file

The database file must be on a NetWare volume. A typical filename is of the form DB:\database\sales.db. You can load the server from a client machine using the Novell remote console utility. See your Novell documentation for details. You can put the command line into your Novell autoexec.ncf file so Adaptive Server Anywhere loads automatically each time you start the NetWare server. There is no personal server for Novell NetWare, just a network server.

What else is there to it?
Although you can start a personal server in the simple way described above, there are many other aspects to running a database server in a production environment. For example: ♦ You can choose from many command-line options or switches to specify such features as how much memory to use as cache, how many CPUs to use (on multi-processor machines), and the network protocols to use (network server only). The command-line switches are one of the major ways of tuning Adaptive Server Anywhere behavior and performance. You can run the server as a service under Windows NT. This allows it to keep running even when you log off the machine. You can start the personal server from an application, and shut it down when the application has finished with it. This is typical when using the database server an embedded database.

♦ ♦

The remainder of this chapter describes these options in more detail.

6

Chapter 1 Running the Database Server

Starting the server
The general form for the server command line is as follows:
executable [ server-switches ] [ database-file [ database-switches ], ...]

If you supply no switches and no database file, then on Windows CE/95/98 and Windows NT operating systems a dialog box is displayed, allowing you to use a Browse button to locate your database file. The elements of the database server command line include the following: ♦
Executable This can be either the personal server or the network server. For the file names on different operating systems, see "Introduction" on page 4.

In this chapter, unless discussing network-specific options, we use the personal server in sample command lines. The network server takes a very similar set of command-line options. ♦ ♦
Server switches Database file

These options control the behavior of the database server, for all running databases.

You can enter zero, one, or more database file names on the command line. Each of these databases starts and remains available for applications.
Caution The database file and the transaction log file must be located on the same physical machine as the database server. Database files and transaction log files located on a network drive can lead to poor performance and data corruption.

Database switches

For each database file you start, you can provide database switches that control certain aspects of its behavior.

$ In this section, we look at some of the more important and commonlyused options. For full reference information on each of these switches, see "The database server" on page 14 of the book ASA Reference. In examples throughout this chapter where there are several command-line options, we show them for clarity on separate lines, as they could be written in a configuration file. If you enter them directly on a command line, you must enter them all on one line. Case sensitivity Command-line parameters are generally case sensitive. You should enter all parameters in lower case.

7

Starting the server

Listing available command-line switches

v To list the database server command-line switches:

Open a command prompt, and enter the following command:
dbeng7 -?

8

Chapter 1 Running the Database Server

Some common command-line switches
This section describes some of the most common command-line switches, and points out when you may wish to use them. They are: ♦ ♦ ♦ ♦ ♦ ♦ ♦ Using configuration files Naming the server and the databases Performance Permissions Maximum page size Special modes Network communications (network server only)

Using configuration files
If you use an extensive set of command-line options, you can store them in a configuration file, and invoke that file on a server command line. The configuration file can contain switches on several lines. For example, the following configuration file starts the personal database server and the sample database. It sets a cache of 10 Mb, and names this instance of the personal server Elora.
-n Elora -c 10M path\asademo.db

where path is the name of your Adaptive Server Anywhere installation directory. On UNIX, you would use a forward slash instead of the backslash in the file path. If you name the file sample.cfg, you could use these command-line options as follows:
dbeng7 @sample.cfg

Naming the server and the databases
You can use the –n command-line option as a database switch (to name the database) or as a server switch (to name the server).

9

Some common command-line switches
The server and database names are among the connection parameters that client applications may use when connecting to a database. The server name appears on the desktop icon and on the title bar of the server window. Naming databases You may want to provide a database name to provide a more meaningful name than the file name for users of client applications. The database will be identified by that name until it is stopped. If you don’t provide a database name, the default name is the root of the database file name (the file name without the .db extension). For example, in the following command line the first database is named asademo, and the second sample.
dbeng7 asademo.db sample.db

You can name databases by supplying a –n switch following the database file. For example, the following command line starts the sample database and names it MyDB:
dbeng7 asademo.db -n MyDB

Naming the server

You may want to provide a database server name to avoid conflicts with other server names on your network, or to provide a meaningful name for users of client applications. The server keeps its name for its lifetime (until it is shut down). If you don’t provide a server name, the server is given the name of the first database started. You can name the server by supplying a –n switch before the first database file. For example, the following command line starts a server on the asademo database, and gives it the name Cambridge:
dbeng7 –n Cambridge asademo.db

If you supply a server name, you can start a database server with no database started. The following command starts a server named Galt with no database started:
dbeng7 –n Galt

$ For information about starting databases on a running server, see
"Starting and stopping databases" on page 17. Case sensitivity Server names and database names are case insensitive as long as the character set is single-byte. For more information, see "Connection strings and character sets" on page 312.

Controlling performance and memory from the command line
Several command-line options can have a major impact on database server performance, including: 10

Chapter 1 Running the Database Server

Cache size

The –c switch controls the amount of memory that Adaptive Server Anywhere uses as a cache. This can be a major factor in affecting performance. Generally speaking, the more memory made available to the database server, the faster it performs. The cache holds information that may be required more than once. Accessing information in cache is many times faster than accessing it from disk. The default initial cache size is computed based on the amount of physical memory, the operating system, and the size of the database files. On Windows NT, Windows 95/98, and UNIX the database server takes additional cache when the available cache is exhausted.

$ For a detailed description of performance tuning, see "Monitoring
and Improving Performance" on page 799. For information on controlling cache size, see "Cache size" on page 17 of the book ASA Reference. ♦
Number of processors If you are running on a multi-processor machine, you can set the number of processors with the -gt option.

$ For more information, see "–gt command-line option" on page 30
of the book ASA Reference. ♦
Other performance-related switches There are several switches available for tuning network performance, including -gb (database process priority), and -u (buffered disk I/O).

$ For a full list of startup options, see "The database server" on
page 14 of the book ASA Reference.

Controlling permissions from the command line
Some command-line options control the permissions required to carry out certain global operations, including permissions to start and stop databases, load and unload data, and create and delete database files.

$ For more information, see "Running the database server in a secure
fashion" on page 782

Setting a maximum page size
The database server cache is arranged in pages—fixed-size areas of memory. Since the server uses a single cache for its lifetime (until it is shut down), all pages must have the same size.

11

Some common command-line switches
A database file is also arranged in pages, with a size that is specified on the command line. Every database page must fit into a cache page. By default, the server page size is the same as the largest page size of the databases on the command line. Once the server starts, you cannot start a database with a larger page size than the server. To allow databases with larger page sizes to be started after startup, you can force the server to start with a specified page size using the – gp option. If you use larger page sizes, remember to increase your cache size. A cache of the same size will accommodate only a fraction of the number of the larger pages, leaving less flexibility in arranging the space. The following command starts a server that reserves an 8 Mb cache and can accommodate databases of page sizes up to 4096 bytes.
dbsrv7 –gp 4096 –c 8M –n myserver

Running in special modes
You can run Adaptive Server Anywhere in special modes for particular purposes. ♦
Read-only You can run databases in read-only mode by supplying the -r command-line switch.

$ For more information, see "–r command-line option" on page 33 of
the book ASA Reference. ♦
Bulk load This is useful when loading large quantities of data into a database through the Interactive SQL INPUT command. Do not use the –b option if you are using LOAD TABLE to bulk load data.

$ For more information, see "–b command-line option" on page 20
of the book ASA Reference, and "Importing and Exporting Data" on page 693. ♦
Starting without a transaction log Use the -f database option for recoveryeither to force the database server to start after the transaction log has been lost, or to force the database server to start using a transaction log it would otherwise not find. Note that -f is a database option, not a server option.

Once the recovery is complete, you should stop your server and restart without the -f option.

$ For more information, see "The database server" on page 14 of the
book ASA Reference.

12

Chapter 1 Running the Database Server

Selecting communications protocols
Any communication between a client application and a database server requires a communications protocol. Adaptive Server Anywhere supports a set of communications protocols for communications across networks and for same-machine communications. By default, the database server starts up all available protocols. You can limit the protocols available to a database server by using the –x command-line switch. On the client side, many of the same options can be controlled using the CommLinks connection parameter. Available protocols for the personal server The personal database server (dbeng7.exe) supports the following protocols: ♦ ♦
Shared memory

This protocol is for same-machine communications, and always remains available. It is available on all platforms.

TCP/IP This protocol is for same-machine communications only, from TDS clients, Open Client or the jConnect JDBC driver. You must run TCP/IP if you wish to connect from Open Client or jConnect.

$ For more information on TDS clients, see "Adaptive Server
Anywhere as an Open Server" on page 989. ♦
Named Pipes Provided on Windows NT only, named pipes is for same machine communications for applications that wish to run under a certified security environment.

Available protocols for the network server

The network database server (dbsrv7.exe) supports the following protocols: ♦ ♦ ♦ ♦
Shared memory SPX

This protocol is for same-machine communications, and always remains available. It is available on all platforms. This protocol is supported on all platforms except for UNIX. This protocol is supported on all platforms.

TCP/IP IPX

This protocol is supported on all platforms except for UNIX. Although IPX is still available, it is recommended that you now use SPX instead of IPX. This protocol is supported on all platforms except for NetWare and UNIX.

♦ ♦

NetBIOS

Named Pipes Provided on Windows NT only, named pipes is for same machine communications for applications that wish to run under a certified security environment.

$ For more information on running the server using these options, see
"Supported network protocols" on page 94.

13

Some common command-line switches

Specifying protocols

You can instruct a server to use only some of the available network protocols when starting up, by using the –x command-line switch. The following command starts a server using the TCP/IP and SPX protocols:
dbsrv7 –x "tcpip,spx"

Although not strictly required in this example, the quotes are necessary if there are spaces in any of the arguments to –x. You can add additional parameters to tune the behavior of the server for each protocol. For example, the following command line (entered all on one line) instructs the server to use two network cards, one with a specified port number.
dbsrv7 -x "tcpip{MyIP=192.75.209.12:2367,192.75.209.32}" path\asademo.db

$ For detailed descriptions of the available network communications
parameters that can serve as part of the –x switch, see "Network communications parameters" on page 65 of the book ASA Reference.

14

Chapter 1 Running the Database Server

Stopping the database server
You can stop the database server by: ♦ ♦ Clicking SHUTDOWN on the database server window. Using the dbstop command-line utility. The dbstop utility is particularly useful in batch files, or for stopping a server on another machine. It requires a connection string on its command line. ♦ Letting it shut down automatically by default when the application disconnects. (This only works if the server is a personal server started by an application connection string.) Pressing q when the server display window on UNIX or NetWare machines has the focus. Start a server. For example, the following command executed from the Adaptive Server Anywhere installation directory starts a server named Ottawa using the sample database:
dbsrv7 –n Ottawa asademo.db


Examples

1

2

Stop the server using dbstop:
dbstop –c "eng=Ottawa;uid=dba;pwd=sql"

$ For information on dbstop command-line switches, see "The dbstop command-line utility" on page 130 of the book ASA Reference.
Who can stop the server?
When you start a server, you can use the –gk option to set the level of permissions required for users to stop the server with dbstop. The default level of permissions required is dba, but you can also set the value to all or none. (Interactively, of course, anybody at the machine can click Shutdown on the server window.)

Shutting down operating system sessions
If you close an operating system session where a database server is running, or if you use an operating system command to stop the database server, the server shuts down, but not cleanly. Next time the database loads, recovery will be required, and happens automatically (see "Backup and Data Recovery" on page 645).

15

Stopping the database server
It is better to stop the database server explicitly before closing the operating system session. On NetWare, however, shutting down the NetWare server machine properly does stop the database server cleanly. Examples of commands that will not stop a server cleanly include: ♦ ♦ Stopping the process in Windows NT Task Manager. Using a UNIX slay or kill command.

16

Chapter 1 Running the Database Server

Starting and stopping databases
A database server can have more than one database loaded at a time. You can start databases and start the server at the same time, as follows:
dbeng7 asademo sample

Starting a database on a running server

You can also start databases after starting a server, in one of the following ways: ♦ While connected to a server, connect to a database using a DBF parameter. This parameter specifies a database file for a new connection. The database file is started on the current server.

$ For more information, see "Connecting to an embedded database"
on page 43. ♦ Use the START DATABASE statement, or select Start Database from the File menu in Sybase Central when you have a server selected.

$ For a description, see "START DATABASE statement" on
page 620 of the book ASA Reference. Limitations ♦ The server holds database information in memory using pages of a fixed size. Once a server has been started, you cannot start a database that has a larger page size than the server. The -gd server command-line option determines the permissions required to start databases.

♦ Stopping a database

You can stop a database by: ♦ Disconnecting from a database started by a connection string. Unless you explicitly set the AUTOSTOP connection parameter to NO this happens automatically.

$ For information, see "AutoStop connection parameter" on page 50
of the book ASA Reference. ♦ Using the STOP DATABASE statement from Interactive SQL or Embedded SQL.

$ For a description, see "STOP DATABASE statement" on page 625
of the book ASA Reference.

17

Running the server outside the current session

Running the server outside the current session
When you log on to a computer using a user ID and a password, you establish a session. When you start a database server, or any other application, it runs within that session. When you log off the computer, all applications associated with the session terminate. It is common to require database servers to be available all the time. To make this easier, you can run Adaptive Server Anywhere for Windows NT and for UNIX in such a way that, when you log off the computer, the database server remains running. The way you do this depends on your operating system. ♦
UNIX daemon You can run the UNIX database server as a daemon by using the -ud command-line option, enabling the database server to run

in the background, and to continue running after you log off. ♦
Windows NT service

You can run the Windows NT database server as a service. This has many convenient properties for running high availability servers.

Running the UNIX database server as a daemon
To run the UNIX database server in the background, and to enable it to run independently of the current session, you run it as a daemon.
Do not use ’&’ to run the database server in the background

If you use the UNIX & (ampersand) command to run the database server in the background, it will not work. You must instead run the database server as a daemon.
v To run the UNIX database server as a daemon:

Use the -ud command-line option when starting the database server. For example:
dbsrv7 -ud asademo

Understanding Windows NT services
Although you can run the database server like any other Windows NT program rather than as a service, there are limitations to running it as a standard program, particularly in multi-user environments. 18

Chapter 1 Running the Database Server

Limitations of running as a standard executable

When you start a program, it runs under your Windows NT login session, which means that if you log off the computer, the program terminates. Only one person logs onto Windows NT (on any one computer) at one time. This restricts the use of the computer if you wish to keep a program running much of the time, as is commonly the case with database servers. You must stay logged onto the computer running the database server for the database server to keep running. This can also present a security risk as the Windows NT computer must be left in a logged on state. Installing an application as a Windows NT service enables it to run even when you log off. When you start a service, it logs on using a special system account called LocalSystem (or using another account you specify). Since the service is not tied to the user ID of the person starting it, the service remains open even when that person who started it logs off. You can also configure a service to start automatically when the NT computer starts, before a user logs on.

Advantages of services

Managing services

Sybase Central provides a more convenient and comprehensive way of managing Adaptive Server Anywhere services than the Windows NT services manager.

Programs that can be run as Windows NT services
You can run the following programs as services: ♦ ♦ ♦ ♦ ♦ Network Database Server (dbsrv7.exe) Personal Database Server (dbeng7.exe) SQL Remote Message Agent (dbremote.exe) The MobiLink Synchronization server (dbmlsrv7.exe) A sample application

Not all these applications are supplied in all editions of Adaptive Server Anywhere.

Managing services
You can carry out the following service management tasks from the command-line, or in the Services folder in Sybase Central: ♦ ♦ Add, edit, and remove services. Start, stop, and pause services. 19

Running the server outside the current session
♦ ♦ Modify the parameters governing a service. Add databases to a service, so you can run several databases at one time.
n

The service icons in Sybase Central display the current state of each service using a traffic light icon (running, paused, or stopped).

Adding a service
This section describes how to set up services using Sybase Central and the Service Creation command-line utility.
v To add a new service (Sybase Central):

1 2 3

In Sybase Central, open the Services folder. Double-click Add Service. Follow the instructions in the wizard.

v To add a new service (command-line):

1 2

Choose Start®Programs®Command Prompt to open the command prompt. Execute the Service Creation utility using the -w switch. For example, to create a personal server service called myserv, which starts the specified engine with the specified parameters. The engine runs as the LocalSystem user:

20

Chapter 1 Running the Database Server
dbsvc -as -w myserv E:\asa70\win32\dbeng7 -n william -c 8m e:\asa70\sample.db

$ For more information about the service creation utility and switches,
see "The Service Creation utility" on page 126 of the book ASA Reference. Notes ♦ ♦ Service names must be unique within the first eight characters. If you choose to start a service automatically, it starts whenever the computer starts Windows NT. If you choose to start manually, you need to start the service from Sybase Central each time. You may want to select Disabled if you are setting up a service for future use. Enter command-line switches for the executable, without the executable name itself, in the window. For example, if you want a network server to run using the sample database with a cache size of 20Mb and a name of myserver, you would enter the following in the Parameters box:
-c 20M -n myserver c:\asa7\asademo.db

Line breaks are optional. For information on valid command-line switches, see the description of each program in "Database Administration Utilities" on page 75 of the book ASA Reference. ♦ Choose the account under which the service will run: the special LocalSystem account or another user ID. For more information about this choice, see "Setting the account options" on page 24. If you want the service to be accessible from the Windows NT desktop, check Allow Service to Interact with Desktop. If this option is unchecked, no icon or window appears on the desktop.

$ For more information on the configuration options, see "Configuring
services" on page 22.

Removing a service
Removing a service removes the server name from the list of services. Removing a service does not remove any software from your hard disk. If you wish to re-install a service you previously removed, you need to reenter the command-line switches.
v To remove a service (Sybase Central):

1 2

In Sybase Central, open the Services folder. In the right pane, right-click the icon of the service you want to remove and choose Delete from the popup menu. 21

Running the server outside the current session
v To remove a service (command-line):

1 2

Choose Start®Programs®Command Prompt to open the command prompt. Execute the Service Creation utility using the -d switch. For example, to delete the service called myserv, without prompting for confirmation, enter the following command:
dbsvc -y -d myserv

$ For more information about the service creation utility and switches,
see "The Service Creation utility" on page 126 of the book ASA Reference.

Configuring services
A service runs a database server or other application with a set of commandline switches. For a full description of the command-line switches for each of the administration utilities, see "Database Administration Utilities" on page 75 of the book ASA Reference. In addition to the command-line switches, services accept other parameters that specify the account under which the service runs and the conditions under which it starts.
v To change the parameters for a service:

1 2 3 4

In Sybase Central, open the Services folder. In the right pane, right-click the service you want to change and choose Properties from the popup menu. Alter the parameters as needed on the pages of the Properties dialog. Click OK when finished.

Changes to a service configuration take effect next time someone starts the service. The Startup option is applied the next time Windows NT is started.

$ For a full description of the service property sheet, see "Service
properties" on page 1064.

Setting the startup option
The following options govern startup behavior for Adaptive Server Anywhere services. You can set them on the General tab of the service property sheet.

22

Chapter 1 Running the Database Server

Automatic If you choose the Automatic setting, the service starts whenever the Windows NT operating system is starts. This setting is appropriate for database servers and other applications running all the time. Manual

If you choose the Manual setting, the service starts only when a user with Administrator permissions starts it. For information about Administrator permissions, see your Windows NT documentation. If you choose the Disabled setting, the service will not start.

Disabled

$ For a full description of the service property sheet, see "Service
properties" on page 1064.

Entering command-line switches
The Configuration tab of the service property sheet provides a text box for entering command-line switches for a service. Do not enter the name of the program executable in this box. Examples ♦ To start a network server service running two databases, with a cache size of 20 Mb, and with a name of my_server, you would enter the following in the Parameters box:
-c 20M -n my_server c:\asa7\db_1.db c:\asa7\db_2.db

To start a SQL Remote Message Agent service, connecting to the sample database as user ID DBA, you would enter the following:
-c "uid=dba;pwd=sql;dbn=asademo"

The following figure illustrates a sample property sheet. For a full description of this property sheet, see "Service properties" on page 1064.

23

Running the server outside the current session

$ The command-line switches for a service are the same as those for the executable. For a full description of the command-line switches for each program, see "The Database Server" on page 13 of the book ASA Reference.
Setting the account options
You can choose under which account the service runs. Most services run under the special LocalSystem account, which is the default option for services. You can set the service to log on under another account by opening the Account tab on the service property sheet, and entering the account information. If you choose to run the service under an account other than LocalSystem, that account must have the "log on as a service" privilege. This can be granted from the Windows NT User Manager application, under Advanced Privileges. When an icon appears on the taskbar 24 Whether or not an icon for the service appears on the taskbar or desktop depends on the account you select, and whether Allow Service to Interact with Desktop is checked, as follows:

Chapter 1 Running the Database Server
♦ If a service runs under LocalSystem, and Allow Service to Interact with Desktop is checked in the service property sheet, an icon appears on the desktop of every user logged in to NT on the computer running the service. Consequently, any user can open the application window and stop the program running as a service. If a service runs under LocalSystem, and Allow Service to Interact with Desktop is unchecked in the service property sheet, no icon appears on the desktop for any user. Only users with permissions to change the state of services can stop the service. If a service runs under another account, no icon appears on the desktop. Only users with permissions to change the state of services can stop the service.

Changing the executable file
To change the program executable file associated with a service, click the Configuration tab on the service property sheet and enter the new path and file name in the Path of Executable box. If you move an executable file to a new directory, you must modify this entry.

$ For a full description of the service property sheet, see "Service
properties" on page 1064.

Adding new databases to a service
Each network server or personal server can run more than one database. If you wish to run more than one database at a time, we recommend that you do so by attaching new databases to your existing service, rather than by creating new services.

$ For a full description of the service property sheet, see "Service
properties" on page 1064.
v To add a new database to a service:

1 2 3 4 5

Open the Services folder. Right-click the service and choose Properties from the popup menu. Click the Configuration tab. Add the path and filename of the new database to the end of the list of parameters. Click OK to save the changes. 25

Running the server outside the current session
The new database is started the next time the service starts. Databases can be started on running servers by client applications, such as Interactive SQL.

$ For a description of how to start a database on a server from Interactive
SQL, see "START DATABASE statement" on page 620 of the book ASA Reference.

$ For a description of how to implement this function in an Embedded
SQL application, see the db_start_database function in "The Embedded SQL Interface" on page 7 of the book ASA Programming Interfaces Guide. Starting a database from an application does not attach it to the service. If the service is stopped and restarted, the additional database will not be started automatically.

Setting the service polling frequency
Sybase Central can poll at specified intervals to check the state (started, stopped, paused, removed) of each service, and update the icons to display the current state. The default setting is that polling is off. If you leave it off, you must click Refresh to see changes to the state.
v To set the Sybase Central polling frequency:

1 2 3 4

Open the Services folder. Right-click the service and choose Properties from the popup menu. Click the Polling tab. Set the polling frequency. The frequency applies to all services, not just the one selected. The value you set in this window remains in effect for subsequent sessions, until you change it.

$ For a full description of the service property sheet, see "Service
properties" on page 1064.

Starting, stopping, and pausing services
v To start, stop, or pause a service:

1 2 26

Open the Services folder. Right-click the service and choose Start, Stop, or Pause from the popup menu.

Chapter 1 Running the Database Server
To resume a paused service, right-click the service and choose Continue in the popup menu. If you start a service, it keeps running until you stop it. Closing Sybase Central or logging off does not stop the service. Stopping a service closes all connections to the database and stops the database server. For other applications, the program closes down. Pausing a service prevents any further action being taken by the application. It does not shut the application down or (in the case of server services) close any client connections to the database. Most users do not need to pause their services.

The Windows NT Service Manager
You can use Sybase Central to carry out all the service management for Adaptive Server Anywhere. Although you can use the Windows NT Service Manager in the Control Panel for some tasks, you cannot install or configure an Adaptive Server Anywhere service from the Windows NT Service Manager. If you open the Windows NT Service Manager (from the Windows NT Control Panel), a list of services appears. The names of the Adaptive Server Anywhere services are formed from the Service Name you provided when installing the service, prefixed by Adaptive Server Anywhere. All the installed services appear together in the list.

Running more than one service
This section describes some topics specific to running more than one service at a time.

Service dependencies
In some circumstances you may wish to run more than one executable as a service, and these executables may depend on each other. For example, you may wish to run a server and a SQL Remote Message Agent or Log Transfer Manager to assist in replication. In cases such as these, the services must start in the proper order. If a SQL Remote Message Agent service starts up before the server has started, it fails because it cannot find the server. You can prevent these problems using service groups, which you manage from Sybase Central. 27

Running the server outside the current session

Service groups overview
You can assign each service on your system to be a member of a service group. By default, each service belongs to a group, as listed in the following table.
Service Network server Personal server SQL Remote Message Agent MobiLink Synchronization Server Replication Agent Default group ASANYServer ASANYEngine ASANYRemote ASANYMobiLink ASANYLTM

Before you can configure your services to ensure they start in the correct order, you must check that your service is a member of an appropriate group. You can check which group a service belongs to, and change this group, from Sybase Central.
v To check and change which group a service belongs to:

1 2 3 4 5 6

Open the Services folder. Right-click the service and choose Properties from the popup menu. Click the Dependencies tab. The top text box displays the name of the group the service belongs to. Click Look Up to display a list of available groups on your system. Select one of the groups, or type a name for a new group. Click OK to assign the service to that group.

$ For a full description of the service property sheet, see "Service
properties" on page 1064.

Managing service dependencies
With Sybase Central you can specify dependencies for a service. For example: ♦ You can ensure that at least one member of each of a list of service groups has started before the current service.

28

Chapter 1 Running the Database Server
♦ You can ensure that any number of services start before the current service. For example, you may want to ensure that a particular network server has started before a SQL Remote Message Agent that is to run against that server starts.

v To add a service or group to a list of dependencies:

1 2 3 4 5 6

Open the Services folder. Right-click the service and choose Properties from the popup menu. Click the Dependencies tab. Click Add Service or Add Group to add a service or group to the list of dependencies. Select one of the services or groups from the list. Click OK to add the service or group to the list of dependencies.

$ For a full description of the service property sheet, see "Service
properties" on page 1064.

29

Troubleshooting server startup

Troubleshooting server startup
This section describes some common problems when starting the database server.

Ensure that your transaction log file is valid
The server won’t start if the existing transaction log is invalid. For example, during development you may replace a database file with a new version, without deleting the transaction log at the same time. This causes the transaction log file to be different than the database, and results in an invalid transaction log file.

Ensure that you have sufficient disk space for your temporary file
Adaptive Server Anywhere uses a temporary file to store information while running. This file is stored in the directory pointed to by the TMP or TEMP environment variable, typically c:\temp. If you do not have sufficient disk space available to the temporary directory, you will have problems starting the server.

Ensure that network communication software is running
Appropriate network communication software must be installed and running before you run the database server. If you are running reliable network software with just one network installed, this should be straightforward. If you experience problems, if you are running non-standard software, or if you are running multiple networks, you may want to read the full discussion of network communication issues in "Client/Server Communications" on page 85. You should confirm that other software requiring network communications is working properly before running the database server. For example, if you are using NetBIOS under Windows 95/98 or Windows NT you may want to confirm that the chat or winpopup application is working properly between machines running client and database server software. If you are running under the TCP/IP protocol, you may want to confirm that ping and telnet are working properly. The ping and telnet applications are provided with many TCP/IP protocol stacks. 30

Chapter 1 Running the Database Server

Debugging network communications startup problems
If you are having problems establishing a connection across a network, you can use debugging options at both client and server to diagnose problems. On the server, you use the -z command-line option. The startup information appears on the server window: you can use the -o option to log the results to an output file.

31

Troubleshooting server startup

32

C H A P T E R

2

Connecting to a Database

About this chapter

This chapter describes how client applications connect to databases. It contains information about connecting to databases from ODBC, OLE DB, and embedded SQL applications. It also describes connecting from Sybase Central and Interactive SQL.

$ For information on connecting to a database from Sybase Open Client
applications, see "Adaptive Server Anywhere as an Open Server" on page 989.

$ For information on connecting via JDBC (if you are not working in
Sybase Central or Interactive SQL), see "Data Access Using JDBC" on page 591. Contents
Topic Introduction to connections Connecting from Sybase Central or Interactive SQL Simple connection examples Working with ODBC data sources Connecting from desktop applications to a Windows CE database Connecting to a database using OLE DB Connection parameters Troubleshooting connections Using integrated logins Page 34 38 41 49 59 62 64 67 77

33

Introduction to connections

Introduction to connections
Any client application that uses a database must establish a connection to that database before any work can be done. The connection forms a channel through which all activity from the client application takes place. For example, your user ID determines permissions to carry out actions on the database—and the database server has your user ID because it is part of the request to establish a connection. How connections are established To establish a connection, the client application calls functions in one of the Adaptive Server Anywhere interfaces. Adaptive Server Anywhere provides the following interfaces: ♦ ♦ ♦ ♦
ODBC OLE DB

ODBC connections are discussed in this chapter. OLE DB connections are discussed in this chapter. Embedded SQL connections are discussed in this

Embedded SQL

chapter.
Sybase Open Client

Open Client connections are not discussed in this chapter. For information on connecting from Open Client applications, see "Adaptive Server Anywhere as an Open Server" on page 989. Sybase Central and Interactive SQL have the connection logic described in this chapter built into them. Other JDBC applications cannot use the connection logic discussed in this chapter.

JDBC

$ For general information on connecting via JDBC, see "Data Access
Using JDBC" on page 591. The interface uses connection information included in the call from the client application, perhaps together with information held on disk in a file data source, to locate and connect to a server running the required database. The following figure is a simplified representation of the pieces involved.
Client application Database server

Interface Library

34

Chapter 2 Connecting to a Database

What to read

If you want... An overview of connecting from Sybase Central or Interactive SQL (including a description of the drivers involved) Some examples to get started quickly, including Sybase Central and Interactive SQL scenarios To learn about data sources To learn what connection parameters are available To see an in-depth description of how connections are established To learn about network-specific connection issues. To learn about character set issues affecting connections

Consider reading... "Connecting from Sybase Central or Interactive SQL" on page 38 "Simple connection examples" on page 41. "Working with ODBC data sources" on page 49 "Connection parameters" on page 64. "Troubleshooting connections" on page 67. "Client/Server Communications" on page 85. "Connection strings and character sets" on page 312.

How connection parameters work
When an application connects to a database, it uses a set of connection parameters to define the connection. Connection parameters include information such as the server name, the database name, and a user ID. A keyword-value pair (of the form parameter=value) specifies each connection parameter. For example, you specify the password connection parameter for the default password as follows:
Password=sql

Connection parameters are assembled into connection strings. In a connection string, a semicolon separates each connection parameter, as follows:
ServerName=asademo;DatabaseName=asademo

Representing connection strings

This chapter has many examples of connection strings represented in the following form:
parameter1=value1 parameter2=value2 ...

This is equivalent to the following connection string: 35

Introduction to connections
parameter1=value1;parameter2=value2

You must enter a connection string on a single line, with the parameter settings separated by semicolons.

Connection parameters passed as connection strings
Connection parameters are passed to the interface library as a connection string. This string consists of a set of parameters, separated by semicolons:
parameter1=value1;parameter2=value2;...

In general, the connection string built up by an application and passed to the interface library does not correspond directly to the way a user enters the information. Instead, a user may fill in a dialog box, or the application may read connection information from an initialization file. Many of the Adaptive Server Anywhere utilities accept a connection string as the -c command-line option and pass the connection string on to the interface library without change. For example, the following is a typical Collation utility (dbcollat) command line (which should be entered all on one line):
dbcollat –c "uid=dba;pwd=sql;dbn=asademo" c:\temp\asademo.col

Interactive SQL connection strings

Interactive SQL processes the connection string internally. These utilities do not simply pass on the connection parameters to the interface library. Do not use Interactive SQL to test command strings from a command prompt.

Saving connection parameters in ODBC data sources
Many client applications, including application development systems, use the ODBC interface to access Adaptive Server Anywhere. When connecting to the database, ODBC applications typically use ODBC data sources. An ODBC data source is a set of connection parameters, stored in the registry or in a file. For Adaptive Server Anywhere, ODBC data sources can be used not only by ODBC applications on Windows, but also by other applications: ♦ Adaptive Server Anywhere client applications on UNIX can use ODBC data sources, as well as those on Windows operating systems. On UNIX, the data source is stored as a file.

36

Chapter 2 Connecting to a Database
♦ Adaptive Server Anywhere client applications using the OLE DB or embedded SQL interfaces can use ODBC data sources, as well as ODBC applications. Interactive SQL and Sybase Central can use ODBC data sources.

$ For more information on ODBC data sources, see "Working with
ODBC data sources" on page 49.

37

Connecting from Sybase Central or Interactive SQL

Connecting from Sybase Central or Interactive SQL
To use Sybase Central or Interactive SQL for managing your database, you must first connect to it. In the Connect dialog, you tell Sybase Central or Interactive SQL what database you want to connect to, where it is located, and how you want to connect to it. The connecting process depends on your situation. For example, if you have a server already running on your machine and this server contains only one database, all you have to do in the Connect dialog is provide a user ID and a password. Sybase Central or Interactive SQL then knows to connect immediately to the database on the running server. If this running server has more than one database loaded on it, if it is not yet running, or if it is running on another machine, you need to provide more detailed information in the Connect dialog so that Sybase Central or Interactive SQL knows what database to connect to. This section describes how to access the Connect dialog in Sybase Central and Interactive SQL. It also provides a general description of this dialog; for a more detailed description, see "Connect dialog" on page 1045.

$ For connection examples, including examples for Sybase Central and
Interactive SQL, see "Simple connection examples" on page 41.

Opening the Connect dialog
A common Connect dialog is available in both Sybase Central and Interactive SQL to let you connect to a database. When you start Sybase Central, you need to manually display this dialog. When you start Interactive SQL, the dialog automatically appears; you can also make it appear for a new connection by choosing File®New Window.
v To open the Connect dialog (Sybase Central):

In Sybase Central, choose Tools®Connect. If you have more than one Sybase Central plugin installed, choose Adaptive Server Anywhere from the displayed list. or Click the Connect button on the main toolbar. or Press F11.

38

Chapter 2 Connecting to a Database

Tip

You can make subsequent connections to a given database easier and faster by using a connection profile.
v To display the Connect dialog (Interactive SQL):

1

In Interactive SQL, choose File®New. or Click SQL®Connect.

Once the Connect dialog is displayed, you must specify the connection parameters you need to connect. For example, you can connect to the Adaptive Server Anywhere sample database by choosing ASA 7.0 Sample from the ODBC Data Source Name list and clicking OK.

Specifying a driver for your connection
When you are working with a database, all your requests and commands go through a driver to the database itself. Sybase Central and Interactive SQL support two main types of drivers: a JDBC driver (called jConnect) and an ODBC driver (called JDBC-ODBC Bridge). Both are included with Adaptive Server Anywhere. Sybase jConnect is a fully supported, fully featured JDBC driver. This driver is platform-independent and offers better performance than JDBC-ODBC Bridge. It is enabled by default. The JDBC-ODBC Bridge driver is a Sun product and is available solely as an alternative method of connecting. The jConnect driver is recommended over JDBC-ODBC Bridge. As you connect to a database in the Connect dialog, you can choose which driver you want to use for the connection. This is an optional configuration; the jConnect driver is the preferred driver and is automatically used for all connections unless you specify otherwise. Data sources and the jConnect driver As a general rule, the jConnect driver cannot use ODBC data sources. However, Sybase Central and Interactive SQL are special cases. When you use the jConnect driver in either of them, you can specify an ODBC data source to establish a connection. For example, you can connect to the sample database using the ASA 7.0 Sample data source, even if you are using the jConnect driver. This customized functionality is only available while you are working in Sybase Central or Interactive SQL. If you are constructing a JDBC application, do not try to use a data source to connect to a database. 39

Connecting from Sybase Central or Interactive SQL
v To specify a driver for the connection:

1 2 3

In Sybase Central, choose Tools®Connect to open the Connect dialog. Configure the necessary settings on the Identification and Database tabs of the dialog. On the Advanced tab of the dialog, select either jConnect5 or JDBCODBC Bridge.

$ For more information on ODBC and JDBC drivers, see "Using the
Sybase jConnect JDBC driver" on page 612, and "Working with ODBC data sources" on page 49.

Working with the Connect dialog
The Connect dialog lets you define parameters for connecting to a server or database. The same dialog is used in both Sybase Central and Interactive SQL. The Connect dialog has the following tabs: ♦ ♦ ♦ The Identification tab lets you identify yourself to the database and specify a data source. The Database tab lets you identify a server and/or database to connect to. The Advanced tab lets you add additional connection parameters and specify a driver for the connection.

In Sybase Central, after you connect successfully, the database name appears in the left pane of the main window, under the server that it is running on. The user ID for the connection is shown in brackets after the database name. In Interactive SQL, the connection information (including the database name, your user ID, and the database server) appears on a title bar above the SQL Statements pane.

$ For a detailed description of the individual fields in the Connect dialog,
see "Connect dialog" on page 1045.

40

Chapter 2 Connecting to a Database

Simple connection examples
Although the connection model for Adaptive Server Anywhere is configurable, and can become complex, in many cases connecting to a database is very simple. Who should read this section? This section describes some simple cases of applications connecting to an Adaptive Server Anywhere database. This section may be all you need to get started.

$ For more detailed information on available connection parameters and
their use, see "Connection parameters" on page 64.

Connecting to the sample database from Sybase Central or Interactive SQL
Many examples and exercises throughout the documentation start by connecting to the sample database from Sybase Central or Interactive SQL.
v To connect to the sample database (Sybase Central):

1 2 3 4

To start Sybase Central: from the Start menu, choose Programs®Sybase SQL Anywhere 7®Sybase Central 4.0. To open the Connect dialog: from the Tools menu, choose Connect. Select the ODBC Data Source Name option and click Browse. Select ASA 7.0 Sample and click OK.

v To connect to the sample database (Interactive SQL):

1

To start Interactive SQL: from the Start menu, choose Programs®Sybase SQL Anywhere 7®Adaptive Server Anywhere 7®Interactive SQL. To open the Connect dialog: from the SQL menu, choose Connect. Select the ODBC Data Source Name option and click Browse. Select ASA 7.0 Sample and click OK.

2 3 4 Note

You do not need to enter a user ID and a password for this connection because the data source already contains this information.

41

Simple connection examples

Connecting to a database on your own machine from Sybase Central or Interactive SQL
The simplest connection scenario is when the database you want to connect to resides on your own machine. If this is the case for you, ask yourself the following questions: ♦ Is the database already running on a server? If so, you can specify fewer parameters in the Connect dialog. If not, you need to identify the database file so that Sybase Central or Interactive SQL can start it for you. Are there multiple databases running on your machine? If so, you need to tell Sybase Central or Interactive SQL which database in particular to connect to. If there is only one, Sybase Central or Interactive SQL assumes that it is the one you want to connect to, and you don’t need to specify it in the Connect dialog.

The procedures below depend on your answers to these questions.
v To connect to a database on an already-running local server:

1 2 3

Start Sybase Central or Interactive SQL and open the Connect dialog (if it doesn’t appear automatically). On the Identification tab of the dialog, enter a user ID and a password. Do one of the following: ♦ ♦ If the server only contains the one database, click OK to connect to it. If the server contains multiple databases, click the Database tab of the dialog and specify a database name. This is usually the database file name, without the path or extension.

v To connect to a database that is not yet running:

1 2 3 4 5

Start Sybase Central or Interactive SQL and open the Connect dialog (if it doesn’t appear automatically). On the Identification tab of the dialog, enter a user ID and a password. Click the Database tab of the dialog. Specify a file in the Database File field (including the full path, name, and extension). You can search for a file by clicking Browse. If you want the database name for subsequent connections to be different from the file name, enter a name in the Database Name field (without including a path or extension).

42

Chapter 2 Connecting to a Database

Tips

If the database is already loaded (started) on the server, you only need to provide a database name for a successful connection. The database file is not necessary. You can connect using a data source (a stored set of connection parameters) for either of the above scenarios by selecting the appropriate data source option at the bottom of the Identification tab of the Connect dialog. For information about using data sources in conjunction with the JDBC driver (jConnect), see "Specifying a driver for your connection" on page 39.

$ See also
♦ ♦ "Opening the Connect dialog" on page 38 "Simple connection examples" on page 41

Connecting to an embedded database
An embedded database, designed for use by a single application, runs on the same machine as the application and is largely hidden from the application user. When an application uses an embedded database, the personal server is generally not running when the application connects. In this case, you can start the database using the connection string, and by specifying the database file in the DatabaseFile (DBF) parameter of the connection string. Using the DBF parameter The DBF parameter specifies which database file to use. The database file automatically loads onto the default server, or starts a server if none is running. The database unloads when there are no more connections to the database (generally when the application that started the connection disconnects). If the connection started the server, it stops once the database unloads. The following connection parameters show how to load the sample database as an embedded database:
dbf=path\asademo.db uid=dba pwd=sql

where path is the name of your Adaptive Server Anywhere installation directory.

43

Simple connection examples

Using the Start parameter

The following connection parameters show how you can customize the startup of the sample database as an embedded database. This is useful if you wish to use command-line options, such as the cache size:
Start=dbeng7 -c 8M dbf=path\asademo.db uid=dba pwd=sql

$ See also
♦ ♦ "Opening the Connect dialog" on page 38 "Simple connection examples" on page 41

Connecting using a data source
You can save sets of connection parameters in a data source. ODBC and Embedded SQL applications use data sources. You can create data sources from the ODBC Administrator. If you are constructing an application, you should only use data sources for ODBC applications. It is possible to specify data sources when you are using the JDBC driver (jConnect), but only within Sybase Central or Interactive SQL. For more information, see "Specifying a driver for your connection" on page 39.
v To connect from Sybase Central or Interactive SQL using a data source:

1 2 3

Start Sybase Central or Interactive SQL and open the Connect dialog (if it doesn’t appear automatically). On the Identification tab, enter a user ID and password. On the lower half of the Identification tab, do one of the following: ♦ Select the ODBC Data Source Name option and specify a data source name (equivalent to the DSN connection parameter, which references a data source in the registry). You can view a list of data sources by clicking Browse. Select the ODBC Data Source File option and specify a data source file (equivalent to the FileDSN connection parameter, which references a data source held in a file). You can search for a file by clicking Browse.

The ASA 7.0 Sample data source holds a set of connection parameters, including the database file and a Start parameter to start the database. 44

Chapter 2 Connecting to a Database

$ See also
♦ ♦ "Opening the Connect dialog" on page 38 "Simple connection examples" on page 41

Connecting to a server on a network
To connect to a database running on a network server somewhere on a local or wide area network, the client software must locate the database server. Adaptive Server Anywhere provides a network library to handle this task. Network connections occur over a network protocol. Several protocols are supported, including TCP/IP, SPX, and NetBIOS.

$ For a full description of client/server communications over a network,
see "Client/Server Communications" on page 85.

Interface library

Network
Specifying the server Adaptive Server Anywhere server names must be unique on a local domain for a given network protocol. The following connection parameters provide a simple example for connecting to a server running elsewhere on a network:
eng=svr_name dbn=db_name uid=user_id pwd=password CommLinks=all

The client library first looks for a personal server of the given name, and then looks on the network for a server of the given name.

$ The above example finds any server started using the default port number. However, you can start servers using other port numbers by providing more information in the CommLinks parameter. For information, see "CommLinks connection parameter" on page 52 of the book ASA Reference.
45

Simple connection examples

Specifying the protocol

If several protocols are available, you can instruct the network library which ones to use to improve performance. The following parameters use only the TCP/IP protocol:
eng=svr_name dbn=db_name uid=user_id pwd=password CommLinks=tcpip

The network library searches for a server by broadcasting over the network, which can be a time-consuming process. Once the network library locates a server, the client library stores its name and network address in a file, and reuses this entry for subsequent connection attempts to that server using the specified protocol. Subsequent connections can be many times faster than a connection achieved by broadcast.

$ Many other connection parameters are available to assist Adaptive
Server Anywhere in locating a server efficiently over a network. For more information see "Network communications parameters" on page 65 of the book ASA Reference.
v To connect to a database on a network server from Sybase Central or Interactive SQL:

1 2 3 4

Start Sybase Central or Interactive SQL and open the Connect dialog (if it does not appear automatically). On the Identification tab of the dialog, enter a user ID and a password. On the Database tab of the dialog, enter the Server Name. You can search for a server by clicking Find. Identify the database by specifying a database name.
Tips

You can connect using a data source (a stored set of connection parameters) by selecting the appropriate data source option at the bottom of the Identification tab of the Connect dialog. For information about using data sources in conjunction with the JDBC driver (jConnect), see "Specifying a driver for your connection" on page 39. By default, all network connections in Sybase Central and Interactive SQL use the TCP/IP network protocol. For more information about network protocol options, see "Network communication concepts" on page 86.

$ See also
46

Chapter 2 Connecting to a Database
♦ ♦ "Opening the Connect dialog" on page 38 "Simple connection examples" on page 41

Using default connection parameters
You can leave many connection parameters unspecified, and instead use the default behavior to make a connection. Be cautious about relying on default behavior in production environments, especially if you distribute your application to customers who may install other Adaptive Server Anywhere applications on their machine. Default database server and database Default database server If a single personal server is running, with a single loaded database, you can connect using entirely default parameters:
uid=user_id pwd=password

If more than one database is loaded on a single personal server, you can leave the server as a default, but you need to specify the database you wish to connect to:
dbn=db_name uid=user_id pwd=password

Default database

If more than one server is running, you need to specify which server you wish to connect to. If only one database is loaded on that server, you do not need to specify the database name. The following connection string connects to a named server, using the default database:
eng=server_name uid=user_id pwd=password

No defaults

The following connection string connects to a named server, using a named database:
eng=server_name dbn=db_name uid=user_id pwd=password

$ For more information about default behavior, see "Troubleshooting
connections" on page 67.

47

Simple connection examples

Connecting from Adaptive Server Anywhere utilities
All Adaptive Server Anywhere database utilities that communicate with the server (rather than acting directly on database files) do so using Embedded SQL. They follow the procedure outlined in "Troubleshooting connections" on page 67 when connecting to a database. How database tools obtain connection parameter values Many of the administration utilities obtain the connection parameter values by: 1 Using values specified on the command line (if there are any). For example, the following command starts a backup of the default database on the default server using the user ID DBA and the password SQL:
dbbackup -c "uid=dba;pwd=sql" c:\backup

2

Using the SQLCONNECT environment variable settings if any command line values are missing. Adaptive Server Anywhere does not set this variable automatically.

$ For a description of the SQLCONNECT environment variable, see
"Environment variables" on page 6 of the book ASA Reference. 3 Prompting you for a user ID and password to connect to the default database on the default server, if parameters are not set in the command line, or the SQLCONNECT environment variable.

$ For a description of command line switches for each database tool, see
the chapter "Database Administration Utilities" on page 75 of the book ASA Reference.

48

Chapter 2 Connecting to a Database

Working with ODBC data sources
Microsoft Corporation defines the Open Database Connectivity (ODBC) interface, which is a standard interface for connecting client applications to database management systems in the Windows 95/98 and Windows NT environments. Many client applications, including application development systems, use the ODBC interface to access a wide range of database systems. Where data sources are held You connect to an ODBC database using an ODBC data source. You need an ODBC data source on the client computer for each database you want to connect to. The ODBC data source contains a set of connection parameters. You can store sets of Adaptive Server Anywhere connection parameters as an ODBC data source, in either the system registry or as files. If you have a data source, your connection string can simply name the data source to use: ♦
Data source Use the DSN connection parameter to reference a data source in the registry: DSN=my data source

File data source

Use the FileDSN connection parameter to reference a data source held in a file:
FileDSN=mysource.dsn

For Adaptive Server Anywhere, the use of ODBC data sources goes beyond Windows applications using the ODBC interface: ♦ ♦ Adaptive Server Anywhere client applications on UNIX can use ODBC data sources, as well as those on Windows operating systems. Adaptive Server Anywhere client applications using the OLE DB or embedded SQL interfaces can use ODBC data sources, as well as ODBC applications. Interactive SQL and Sybase Central can use ODBC data sources.

Creating an ODBC data source
You can create ODBC data sources on Windows 95/98 and Windows NT operating systems using the ODBC Administrator, which provides a central place for creating and managing ODBC data sources. Adaptive Server Anywhere also includes a cross-platform command-line utility named dbdsn to create data sources. 49

Working with ODBC data sources

Before you begin

This section describes how to create an ODBC data source. Before you create a data source, you need to know which connection parameters you want to include in it.

$ For more information, see "Simple connection examples" on page 41,
and "Connection parameters" on page 64. ODBC Administrator On Windows 95/98 and Windows NT, you can use the Microsoft ODBC Administrator to create and edit data sources. You can work with User Data Sources, File Data Sources, and System Data Sources in this utility.
v To create an ODBC data source (ODBC Administrator):

1

Start the ODBC Administrator: In Sybase Central, choose Tools®Adaptive Server Anywhere®ODBC Administrator. or From the Windows Start menu, choose Programs®Sybase SQL Anywhere 7®Adaptive Server Anywhere 7®ODBC Administrator. The ODBC Data Source Administrator appears.

2

Click Add. The Create New Data Source wizard appears.

50

Chapter 2 Connecting to a Database
3 From the list of drivers, choose Adaptive Server Anywhere 7.0, and click Finish. The ODBC Configuration for Adaptive Server Anywhere window appears.

Most of the fields in this window are optional. Click the question mark at the top right of the window and click a dialog field to find more information about that field.

$ For more information about the fields in the dialog, see
"Configuring ODBC data sources using the ODBC Administrator" on page 52. 4 When you have specified the parameters you need, click OK to close the window and create the data source.

To edit a data source, find and select one in the ODBC Administrator main window and click Configure.

51

Working with ODBC data sources
You can create User Data Sources using the dbdsn command-line utility. You cannot create File Data Sources or System Data Sources. File and System Data Sources are limited to Windows operating systems only, and you can use the ODBC Administrator to create them.
v To create an ODBC data source (Command line):

Creating an ODBC data source from the command line

1 2

Open a command prompt. Enter a dbdsn command, specifying the connection parameters you wish to use. For example, the following command creates a data source for the Adaptive Server Anywhere sample database. The command must be entered on one line:

dbdsn –w "My DSN" "uid=DBA;pwd=SQL;dbf=c:\Program Files\Sybase\SQL Anywhere 7\asademo.db"

$ For more information on the dbdsn utility, see "The Data Source
utility" on page 89 of the book ASA Reference.

Configuring ODBC data sources using the ODBC Administrator
This section describes the meaning of each of the options on the ODBC configuration dialog.

ODBC tab
Data source name

The Data Source Name is used to identify the ODBC data source. You can use any descriptive name for the data source (spaces are allowed) but it is recommended that you keep the name short, as you may need to enter it in connection strings.

$ For more information, see "DataSourceName connection parameter" on
page 56 of the book ASA Reference.
Description

You may enter an optional longer description of the Data

Source.
Translator Choose Adaptive Server Anywhere 7.0 Translator if your database uses an OEM code page. If your database uses an ANSI code page, which is the default, leave this empty. Isolation level

Select the desired isolation level for this data source:

0

Dirty reads, non-repeatable reads and phantom rows may occur. This is the default.

52

Chapter 2 Connecting to a Database
♦ ♦ ♦
1 2 3

Non-repeatable rows and phantom rows may occur. Dirty reads are prevented. Phantom rows may occur. Dirty reads and non-repeatable rows are prevented. Dirty reads, non-repeatable reads and phantom rows are prevented.

$ For more information, see "Choosing isolation levels" on page 394.
Microsoft applications (keys in SQLStatistics) Check this box if you wish foreign keys to be returned by the SQLStatistics function. The ODBC specifications states that primary and foreign keys should not be returned by SQLStatistics. However, some Microsoft applications (such as Visual Basic and Access) assume that primary and foreign keys are returned by SQLStatistics. Delphi applications Check this box to improve performance for Borland Delphi applications. When this option is checked, one bookmark value is assigned to each row, instead of the two that are otherwise assigned (one for fetching forwards and a different one for fetching backwards).

Delphi cannot handle multiple bookmark values for a row. If the option is unchecked, scrollable cursor performance can suffer since scrolling must always take place from the beginning of the cursor to the row requested in order to get the correct bookmark value.
Prevent driver not capable errors The Adaptive Server Anywhere ODBC driver returns a Driver not capable error code because it does not support qualifiers. Some ODBC applications do not handle this error properly. Check this box to disable this error code, allowing such applications to work. Delay AutoCommit until statement close

Check this box if you wish the Adaptive Server Anywhere ODBC driver to delay the commit operation until a statement has been closed. Select how often you wish a cursor to be redescribed when a procedure is executed or resumed. Tests if the information provided will result in a proper connection. In order for the test to work a user ID and password must have been specified.

Describe cursor behavior

Test Connection

53

Working with ODBC data sources

Login tab
Use integrated login

Connects using an integrated login. The User ID and password do not need to be specified. To use this type of login users must have been granted integrated login permission. The database being connected to must also be set up to accept integrated logins. Only users with DBA access may administer integrated login permissions.

$ For more information, see "Using integrated logins" on page 77.
User ID

Provides a place for you to enter the User ID for the connection.

$ For more information, see "Userid connection parameter" on page 64 of
the book ASA Reference.
Password

Provides a place for you to enter the password for the

connection.

$ For more information, see "Password connection parameter" on
page 61 of the book ASA Reference.
Encrypt password

Check this box if you wish the password to be stored in encrypted form in the profile.

$ For more information, see "EncryptedPassword connection parameter"
on page 58 of the book ASA Reference.

Database tab
Server name Provides a place for you to enter the name of the Adaptive Server Anywhere personal or network server.

$ For more information, see "EngineName connection parameter" on
page 57 of the book ASA Reference.
Start line Enter the server that should be started. Only provide a Start Line parameter if a database server is being connected to that is not currently running. For example:
C:\Program Files\Sybase\ SQL Anywhere 7\win32\dbeng7.exe -c 8m

$ For more information, see "StartLine connection parameter" on page 63
of the book ASA Reference.
Database name

Provides a place for you to enter the name of the Adaptive Server Anywhere database that you wish to connect to. page 55 of the book ASA Reference.

$ For more information, see "DatabaseName connection parameter" on

54

Chapter 2 Connecting to a Database
Database file

Provides a place for you to enter the full path and name of the Adaptive Server Anywhere database file on the server PC. You may also click Browse to locate the file. For example:
C:\Program Files\Sybase\SQL Anywhere 7\asademo.db

$ For more information, see "DatabaseFile connection parameter" on
page 54 of the book ASA Reference.
Automatically start the database if it isn’t running

Causes the database to start automatically (if it is not already running) when you start a new session.

Automatically shut down database after last disconnect

Causes the automatic shutdown of the server after the last user has disconnected. page 50 of the book ASA Reference.

$ For more information, see "AutoStop connection parameter" on

Network tab
Select the network protocols and specify any protocol-specific options where necessary These check boxes specify what protocol or protocols

the ODBC DSN uses to access a network database server. In the adjacent boxes, you may enter communication parameters that establish and tune connections from your client application to a database.

$ For more information see "CommLinks connection parameter" on
page 52 of the book ASA Reference, and "Network communications parameters" on page 65 of the book ASA Reference.
Encrypt all network packets

Enables encryption of packets transmitted from the client machine over the network. By default, network encryption packets is set to OFF. page 58 of the book ASA Reference.

$ For more information, see "Encryption connection parameter" on
Liveness timeout

A liveness packet is sent across a client/server to confirm that a connection is intact. If the client runs for the liveness timeout period without detecting a liveness packet, the communication will be severed. This parameter works only with network server and TCP/IP or IPX communications protocols. The default is 120 seconds.

$ For more information, see "LivenessTimeout connection parameter" on
page 60 of the book ASA Reference.
Buffer size

Sets the maximum size of communication packets, in bytes.

55

Working with ODBC data sources

$ For more information, see "CommBufferSize connection parameter" on
page 51 of the book ASA Reference.
Buffer space Indicates the amount of space to allocate on startup for network buffers, in kilobytes.

$ For more information, see "CommBufferSpace connection parameter"
on page 52 of the book ASA Reference.

Advanced tab
Connection name

The name of the connection that is being created.

Character set Lets you specify a character set (a set of 256 letters, numbers, and symbols specific to a country or language). The ANSI character set is used by Microsoft Windows. An OEM character set is any character set except the ANSI character set. Allow multiple record fetching

Enables multiple records to be retrieved at one time instead of individually. By default, multiple record fetching is allowed. The name of the file in which the debugging information is to be saved.

Display debugging information in a log file

Additional connection parameters Enter any additional switches here. Parameters set throughout the remainder of this dialog take precedence over parameters typed here.

$ For a complete listing, see "Connection parameters" on page 46 of the
book ASA Reference.

Using file data sources on Windows
On Windows operating systems, ODBC data sources are typically stored in the system registry. File data sources are an alternative, which are stored as files. In Windows, file data sources typically have the extension .dsn. They consist of sections, each section starting with a name enclosed in square brackets. DSN files are very similar in layout to initialization files. To connect using a File Data Source, use the FileDSN connection parameter. You cannot use both DSN and FileDSN in the same connection. File data sources can be distributed One benefit of file data sources is that you can distribute the file to users. If the file is placed in the default location for file data sources, it is picked up automatically by ODBC. In this way, managing connections for many users can be made simpler.

56

Chapter 2 Connecting to a Database
Embedded SQL applications can also use ODBC file data sources.
v To create an ODBC file data source (ODBC Administrator):

1 2 3

Start the ODBC Administrator, click the File DSN tab and click Add. Select Adaptive Server Anywhere 7.0 from the list of drivers, and click Next. Follow the instructions to create the data source.

Using ODBC data sources on UNIX
On UNIX operating systems, ODBC data sources are held in a file named .odbc.ini. A sample file looks like this:
[My Data Source] ENG=myserver CommLinks=tcpip(Host=hostname) UID=dba PWD=sql

You can enter any connection parameter in the .odbc.ini file. For a complete list, see "Connection parameters" on page 46 of the book ASA Reference. Network communications parameters are added as part of the CommLinks parameter. For a complete list, see "Network communications parameters" on page 65 of the book ASA Reference. You can create and manage ODBC data sources on UNIX using the dbdsn command-line utility.

$ For more information, see "Creating an ODBC data source" on
page 49, and "The Data Source utility" on page 89 of the book ASA Reference. File location The database server looks for the .odbc.ini file in the following locations: 1 2 3 4 ODBCINI environment variable ODBCHOME and HOME environment variables The user’s home directory The path

57

Working with ODBC data sources

Using ODBC data sources on Windows CE
Windows CE does not provide an ODBC driver manager or an ODBC Administrator. On this platform, Adaptive Server Anywhere uses ODBC data sources stored in files. You can specify either the DSN or the FileDSN keyword to use these data source definitions—on Windows CE (only), DSN and FileDSN are synonyms. Data source location Windows CE searches for the data source files in the following locations: 1 2 The directory from which the ODBC driver ( dbodbc7.dll ) was loaded. This is usually the Windows directory. The directory specified in Location key of the Adaptive Server Anywhere section of the registry. This is usually the same as the Adaptive Server Anywhere installation directory. The default installation directory is:
\Program Files \SQL Anywhere 7 \Windows

Each data source itself is held in a file. The file has the same name as the data source, with an extension of .dsn.

$ For more information about file data sources, see "Using file data
sources on Windows" on page 56.

58

Chapter 2 Connecting to a Database

Connecting from desktop applications to a Windows CE database
You can connect from applications running on a desktop PC, such as Sybase Central or Interactive SQL, to a database server running on a Windows CE device. The connection uses TCP/IP over the ActiveSync link between the desktop machine and the Windows CE device. If you are using an Ethernet connection between your desktop machine and the Windows CE device, or if you are using Windows CE Services 2.2, the following procedure works. If you are using a serial cable connection and ActiveSync 3.0, see the following section.
v To connect from a desktop application to a database server running on Windows CE:

1

Determine the IP address of the server. Start the server on the Windows CE device with the -z option (output extra debug information). For example:
dbsrv7 -z -x tcpip -n TestServer asademo.db

With the -z switch, the server writes out its IP address during startup. The address may change if you disconnect your HPC from the network and then re-connect it. To change between static and dynamic IP assignment for the HPC, configure the settings in the Windows Control Panel. Open Network, and choose the Services tab. Select Remote Access Service and click Properties®Network®TCP/IP Configuration. 2 Create an ODBC profile on your desktop machine. Open the ODBC Administrator, and click Add. Choose Adaptive Server Anywhere 7.0 from the list of drivers and click Finish. The ODBC Configuration for Adaptive Server Anywhere dialog appears. ♦ ♦ ♦ On the Login tab, type a user ID and password. On the Database tab, type the server name. On the Network tab, check TCP/IP, and type the following in the adjacent field:
dobroadcast=direct;host=XXX.XXX.XXX.XXX

where XXX.XXX.XXX.XXX is the server IP address.

59

Connecting from desktop applications to a Windows CE database
♦ 3 4 5 On the ODBC tab, click Test Connection to confirm that your ODBC data source is properly configured.

Exit the ODBC administrator. Ensure the database server is running on your Windows CE machine. On your desktop machine, start an application such as Interactive SQL and select the ODBC data source you have created. The application connects to the Windows CE database.

Using ActiveSync 3.0 and a serial cable
To connect to a Windows CE device from your desktop over a serial cable, Adaptive Server Anywhere uses the TCP/IP protocol. For TCP/IP to work in this context, your ActiveSync installation must be set up to provide a Remote Access Service (RAS) link between desktop machine and Windows CE device. ActiveSync 2.2 automatically installs and configures RAS, and you can connect in a straightforward manner. For information, see "Connecting from desktop applications to a Windows CE database" on page 59. ActiveSync 3.0 does not install and configure RAS. You must install RAS yourself to obtain TCP/IP connectivity to your device over a serial connection. Instructions for installing RAS are provided by Microsoft. They are available at http://support.microsoft.com/support/kb/articles/Q241/2/16.ASP (Microsoft Knowledge Base article Q241216). You must follow these instructions exactly, including re-installing any Windows NT service packs, and granting your user account dial-in access using User Manager. As you follow the instructions, where it says to install your modem, choose Dial-up Networking Serial Cable between 2 PCs instead. Using RAS with ActiveSync The following list includes suggestions for enabling ActiveSync 3.0 connections over a serial connection using RAS: 1 In the ActiveSync Connection Settings, select the checkbox Allow
network (Ethernet) and Remote Access Service (RAS) server connection with desktop computer. You may need to turn off the checkbox Allow serial cable or infrared connection to this COM port.

2 3

On the desktop, using Remote Access Administrator (under Administrative Tools on Windows NT), start RAS on COM1. On the Windows CE device, run the ActiveSync client (repllog.exe on a Windows CE PC). Choose serial connection.

60

Chapter 2 Connecting to a Database
4 5 Wait for up to one minute for a connection to be established. As a test, run the ipconfig utility on Windows NT, and see the 192.168.55.100 static IP of the device. This is the IP you would use when connecting to an Adaptive Server Anywhere database server (for example) running on the CE device. If you switch devices, Stop and Restart the RAS service (or reboot). If everything is set up as above, but you still fail to get a connection from the device to the desktop, you should make sure your Port settings match the baud rates in the Modems Control Panel applet.

6 7

61

Connecting to a database using OLE DB

Connecting to a database using OLE DB
OLE DB uses the Component Object Model (COM) to make data from a variety of sources available to applications. Relational databases are among the classes of data sources that you can access through OLE DB. This section describes how to connect to an Adaptive Server Anywhere database using OLE DB from the following environments: ♦ ♦ Sybase PowerBuilder can access OLE DB data sources, and you can use Adaptive Server Anywhere as a PowerBuilder OLE DB database profile. Microsoft ActiveX Data Objects (ADO) provides a programming interface for OLE DB data sources. You can access Adaptive Server Anywhere from programming tools such as Microsoft Visual Basic.

This section is an introduction to how to use OLE DB from Sybase PowerBuilder and Microsoft ADO environments such as Visual Basic. It is not complete documentation on how to program using ADO or OLE DB. The primary source of information on development topics is your development tool documentation.

$ For more information about OLE DB, see "Introduction to OLE DB"
on page 152 of the book ASA Programming Interfaces Guide.

OLE DB providers
You need an OLE DB provider for each type of data source you wish to access. Each provider is a dynamic-link library. There are two OLE DB providers you can use to access Adaptive Server Anywhere: ♦
Sybase ASA OLE DB provider

The Adaptive Server Anywhere OLE DB provider provides access to Adaptive Server Anywhere as an OLE DB data source without the need for ODBC components. The short name for this provider is ASAProv. When the ASAProv provider is installed, it registers itself. This registration process includes making registry entries in the COM section of the registry, so that ADO can locate the DLL when the ASAProv provider is called. If you change the location of your DLL, you must reregister it.

$ For more information about OLE DB providers, see "Introduction
to OLE DB" on page 152 of the book ASA Programming Interfaces Guide. ♦ 62
Microsoft OLE DB provider for ODBC Microsoft provides an OLE DB provider with a short name of MSDASQL.

Chapter 2 Connecting to a Database
The MSDASQL provider makes ODBC data sources appear as OLE DB data sources. It requires the Adaptive Server Anywhere ODBC driver.

Connecting from ADO
ADO is an object-oriented programming interface. In ADO, the Connection object represents a unique session with a data source. You can use the following Connection object features to initiate a connection: ♦ ♦ The Provider property that holds the name of the provider. If you do not supply a Provider name, ADO uses the MSDASQL provider. The ConnectionString property that holds a connection string. This property holds an Adaptive Server Anywhere connection string, which is used in just the same way as the ODBC driver. You can supply ODBC data source names, or explicit UserID, Password, DatabaseName, and other parameters, just as in other connection strings.

$ For a list of connection parameters, see "Connection parameters"
on page 64. ♦ The Open method initiates a connection.

$ For more information about ADO, see "ADO programming with
Adaptive Server Anywhere" on page 154 of the book ASA Programming Interfaces Guide. Example The following Visual Basic code initiates an OLE DB connection to Adaptive Server Anywhere:
’ Declare the connection object Dim myConn as New ADODB.Connection myConn.Provider = "ASAProv" myConn.ConnectionString = "Data Source=ASA 7.0 Sample" myConn.Open

63

Connection parameters

Connection parameters
The following table lists the Adaptive Server Anywhere connection parameters.

$ For a full description of each of these connection parameters, see
"Connection and Communication Parameters" on page 45 of the book ASA Reference. For character set issues in connection strings, see "Connection strings and character sets" on page 312.
Parameter Agent AppInfo AutoStart AutoStop Charset CommBufferSize CommBufferSpace CommLinks ConnectionName DatabaseFile DatabaseName DatabaseSwitches DataSourceName Debug DisableMultiRowFetch EncryptedPassword Encryption EngineName / ServerName FileDataSourceName ForceStart Integrated LivenessTimeout Short form Agent APP AStart AStop CS CBSize CBSpace Links CON DBF DBN DBS DSN DBG DMRF ENP ENC ENG FileDSN FORCE INT LTO Argument String (Any or Server) String Boolean Boolean String Integer Integer String String String String String String Boolean Boolean Encrypted string Boolean String String Boolean Boolean Integer

64

Chapter 2 Connecting to a Database
Parameter Logfile Password ** StartLine Unconditional Userid ** Short form LOG PWD Start UNC UID Argument String String String Boolean String

** Verbose form of keyword not used by ODBC connection parameters

Notes

♦ ♦ ♦

Boolean values

Boolean (true or false) arguments are either YES, ON, 1, or TRUE if true, or NO, OFF, 0, or FALSE if false. Connection parameters are case insensitive.

Case sensitivity

The connection parameters used by the interface library can be obtained from the following places (in order of precedence): ♦ ♦ ♦
Connection string

You can pass parameters explicitly in the

connection string.
SQLCONNECT environment variable The SQLCONNECT environment variable can store connection parameters. Data sources

ODBC data sources can store parameters.

Character set restrictions

The server name must be composed of the ASCII character set in the range 1 to 127. There is no such limitation on other parameters. strings and character sets" on page 312.

$ For more information on the character set issues, see "Connection

Priority

The following rules govern the priority of parameters:

The entries in a connect string are read left to right. If the same parameter is specified more than once, the last one in the string applies. If a string contains a data source or file data source entry, the profile is read from the configuration file, and the entries from the file are used if they are not already set. For example, if a connection string contains a data source name and sets some of the parameters contained in the data source explicitly, then in case of conflict the explicit parameters are used.

65

Connection parameters

Connection parameter priorities
Connection parameters often provide more than one way of accomplishing a given task. This is particularly the case with embedded databases, where the connection string starts a database server. For example, if your connection starts a database, you can specify the database name using the DBN connection parameter or using the DBS parameter. Here are some recommendations and notes for situations where connection parameters conflict: ♦ ♦
Specify database files using DBF You can specify a database file on the Start parameter or using the DBF parameter (recommended). Specify database names using DBN You can specify a database name on the Start parameter, the DBS parameter, or using the DBN parameter (recommended). Use the Start parameter to specify cache size

Even though you use the DBF connection parameter to specify a database file, you may still want to tune the way in which it starts. You can use the Start parameter to do this. For example, if you are using the Java features of Adaptive Server Anywhere, you should provide additional cache memory on the Start parameter. The following sample set of embedded database connection parameters describes a connection that may use Java features:
DBF=path\asademo.db DBN=Sample ENG=Sample Server UID=dba PWD=sql Start=dbeng7 -c 8M

66

Chapter 2 Connecting to a Database

Troubleshooting connections
Who needs to read this section? In many cases, establishing a connection to a database is straightforward using the information presented in the first part of this chapter. However, if you are having problems establishing connections to a server, you may need to understand the process by which Adaptive Server Anywhere establishes connections in order to resolve your problems. This section describes how Adaptive Server Anywhere connections work. The software follows exactly the same procedure for each of the following types of client application: ♦
ODBC Any ODBC application using the SQLDriverConnect function, which is the common method of connection for ODBC applications. Many application development systems, such as Sybase PowerBuilder and Power++, belong to this class of application. Embedded SQL Any client application using Embedded SQL and using the recommended function for connecting to a database (db_string_connect).

The SQL CONNECT statement is available for Embedded SQL applications and in Interactive SQL. It has two forms: CONNECT AS... and CONNECT USING. All the database administration tools, including Interactive SQL, use db_string_connect.

$ For information on network-specific issues, including connections
across firewalls, see "Client/Server Communications" on page 85.

The steps in establishing a connection
To establish a connection, Adaptive Server Anywhere carries out the following steps: 1 2
Locate the interface library

The client application must locate the ODBC driver or Embedded SQL interface library. Since connection parameters may appear in several places (such as data sources, a connection string assembled by the application, and an environment variable) Adaptive Server Anywhere assembles the parameters into a single list.

Assemble a list of connection parameters

3

Locate a server

Using the connection parameters, Adaptive Server Anywhere locates a database server on your machine or over a network.

67

Troubleshooting connections
4 5
Locate the database

Adaptive Server Anywhere locates the database

you want to connect to.
Start a personal server If Adaptive Server Anywhere fails to locate a server, it attempts to start a personal database server and load the database.

The following sections describe in detail each of these steps.

Locating the interface library
The client application makes a call to one of the Adaptive Server Anywhere interface libraries. In general, the location of this DLL or shared library is transparent to the user. Here we describe how to locate the library, in case of problems. ODBC driver location For ODBC, the interface library is also called an ODBC driver. An ODBC client application calls the ODBC driver manager, and the driver manager locates the Adaptive Server Anywhere driver. The ODBC driver manager looks in the supplied data source in the odbc.ini file or registry to locate the driver. When you create a data source using the ODBC Administrator, Adaptive Server Anywhere fills in the current location for your ODBC driver. Embedded SQL interface library location Embedded SQL applications call the interface library by name. The name of the Adaptive Server Anywhere Embedded SQL interface library is as follows: ♦ ♦ ♦ ♦
Windows NT and Windows 95/98 UNIX

dblib7.dll

dblib7 with an operating-system-specific extension. dblib7.nlm

NetWare

The locations that are searched depend on the operating system:
PC operating systems On PC operating systems such as Windows and Windows NT, files are looked for in the current directory, in the system path, and in the Windows and Windows\system directories. UNIX operating systems On UNIX, files are looked for in the system path and the user library path. NetWare On NetWare, files are looked for in the search path, and in the sys:system directory.

♦ ♦

68

Chapter 2 Connecting to a Database

When the library is located

Once the client application locates the interface library, it passes a connection string to it. The interface library uses the connection string to assemble a list of connection parameters, which it uses to establish a connection to a server.

Assembling a list of connection parameters
The following figure illustrates how the interface libraries assemble the list of connection parameters they use to establish a connection.

Read parameters from the connection string

Read parameters not already specified from SQLCONNECT
Yes

Is there a data source in the parameter list?
No

Does the data source exist?
No

Yes

Is there a compatibility data source?

No

Failure

Yes

Read parameters not already specified from the data source

Connection parameters complete

Notes

Key points from the figure include: ♦
Precedence Parameters held in more than one place are subject to the following order of precedence: Connection string > SQLCONNECT > data source

That is, if a parameter is supplied both in a data source and in a connection string, the connection string value overrides the data source value. ♦
Failure Failure at this stage occurs only if you specify in the connection string or in SQLCONNECT a data source that does not exist in the client connection file.

69

Troubleshooting connections

Common parameters

Depending on other connections already in use, some connection parameters may be ignored, including: ♦
Autostop

Ignored if the database is already loaded.

CommLinks The specifications for a network protocol are ignored if another connection has already set parameters for that protocol. CommBufferSize

♦ ♦ ♦

Ignored if another connection has already set Ignored if another connection has already set

this parameter.
CommBufferSpace

this parameter.
Unconditional Ignored if the database is already loaded or if the server is already running.

The interface library uses the completed list of connection parameters to attempt to connect.

Locating a server
In the next step toward establishing a connection, Adaptive Server Anywhere attempts to locate a server. If the connection parameter list includes a server name (ENG parameter), it carries out a search first for a local server (personal server or network server running on the same machine) of that name, followed by a search over a network. If no ENG parameter is supplied, Adaptive Server Anywhere looks for a default server.

70

Chapter 2 Connecting to a Database

Yes

Is ENG supplied?

No

Is there a local server named ENG?

Is there a default personal server?

No

Yes Yes

Are ports specified Yes in CommLinks already available?

Locate database on server
Yes No

No

Start up required network protocol ports

Attempt to locate a server named ENG using available ports

Can a server be located?

No

Attempt to start a personal server

$ If Adaptive Server Anywhere locates a server, it tries to locate or load
the required database on that server. For information, see "Locating the database" on page 72.

$ If Adaptive Server Anywhere cannot locate a server, it attempts to start
a personal server. For information, see "Starting a personal server" on page 73. Notes ♦ For local connections, locating a server is simple. For connections over a network, you can use the CommLinks parameter to tune the search in many ways by supplying network communication parameters.

71

Troubleshooting connections
♦ The network search involves a search over one or more of the protocols supported by Adaptive Server Anywhere. For each protocol, the network library starts a single port. All connections over that protocol at any one time use a single port. You can specify a set of network communication parameters for each network port in the argument to the CommLinks parameter. Since these parameters are necessary only when the port first starts, the interface library ignores any connection parameters specified in CommLinks for a port already started. Each attempt to locate a server (the local attempt and the attempt for each network port) involves two steps. First, Adaptive Server Anywhere looks in the server name cache to see if a server of that name is available. Second, it uses the available connection parameters to attempt a connection.

Locating the database
If Adaptive Server Anywhere successfully locates a server, it then tries to locate the database. For example:

72

Chapter 2 Connecting to a Database

Is DBN specified?
Yes

No

Is DBF specified?

No

Attempt to connect

Yes

Is there a default database running?

No

Is a database running whose name is the root of DBF?
No Yes

Failure
Yes

Attempt to connect Can the DBF file be located?
Yes

No

Attempt to connect

Load and attempt to connect

Failure

Starting a personal server
If no server can be located, the interface libraries attempt to start a personal server using other parameters. The Start and DBF parameters can be used to start a personal server.

73

Troubleshooting connections

No

Is there a START parameter?

Yes

Is there a DBF parameter?

No

Yes

Failure

Use the START parameter

Attempt to start a personal server on the file

The START parameter takes a personal database server command line. If a START parameter is unavailable, Adaptive Server Anywhere attempts to start a personal server on the file indicated by the DBF. If both an ENG parameter and a DBF parameter appear, the ENG parameter becomes the name of the server.

Server name caching for faster connections
The network library looks for a database server on a network by broadcasting over the network using the CommLinks connection parameter. Tuning the broadcast The CommLinks parameter takes as argument a string listing the protocols to use and, optionally for each protocol, a variety of network communication parameters that tune the broadcast.

$ For a complete listing of network communications parameters, see
"Network communications parameters" on page 65 of the book ASA Reference. Caching server information Broadcasting over large networks searching for a server of a specific name can be time-consuming. To speed up network connections (except for the first connection to a server), when a server is located, the protocol it was found on and its address are saved to a file.

74

Chapter 2 Connecting to a Database
The server information is saved in a file named asasrv.ini, in your Adaptive Server Anywhere executable directory. The file contains a set of sections, each of the following form:
[Server name] Link=protocol_name Address=address_string

How the cache is used

When a connection specifies a server name, and a server with that name is not found, the network library looks first in the server name cache to see if the server is known. If there is an entry for the server name, an attempt is made to connect using the link and address in the cache. If the server is located using this method, the connection is much faster, as no broadcast is involved. If the server is not located using cached information, the connection string information and CommLinks parameter are used to search for the server using a broadcast. If the broadcast is successful, the server name entry in the named cache is overwritten.
Cache precedes CommLinks

If a server name is held in the cache, the cache entry is used before the CommLinks string.

Interactive SQL connections
The Interactive SQL utility has a different behavior from the default Embedded SQL behavior when a CONNECT statement is issued while already connected to a database. If no database or server is specified in the CONNECT statement, Interactive SQL connects to the current database, rather than to the default database. This behavior is required for database reloading operations.

$ For an example, see "CONNECT statement" on page 423 of the book
ASA Reference.

Testing that a server can be found
The dbping command-line utility is provided to help in troubleshooting connections. In particular, you can use it to test if a server with a particular name is available on your network. The dbping utility takes a connection string as a command-line option, but by default only those pieces required to locate a server are used. It does not attempt to start a server. 75

Troubleshooting connections

Examples

The following command line tests to see if a server named Waterloo is available over a TCP/IP connection:
dbping -c "eng=Waterloo;CommLinks=tcpip"

The following command tests to see if a default server is available on the current machine.
dbping

$ For more information on dbping options, see "The Ping utility" on
page 122 of the book ASA Reference.

$ For more information about printing more output during connection
attempts, see "Debug connection parameter" on page 56 of the book ASA Reference. This feature is especially useful when used in conjunction with the "Logfile connection parameter" on page 60 of the book ASA Reference.

76

Chapter 2 Connecting to a Database

Using integrated logins
The integrated login feature allows you to maintain a single user ID and password for both database connections and operating system and/or network logins. This section describes the integrated login feature. Operating systems supported Benefits of an integrated login Integrated login capabilities are available for the Windows NT server only. It is possible for Windows 95/98 clients as well as Windows NT clients to use integrated logins to connect to a network server running on Windows NT. An integrated login is a mapping from one or more Windows NT user profiles to an existing user in a database. A user who has successfully navigated the security for that user profile and logged in to their machine can connect to a database without providing an additional user ID or password. To accomplish this, the database must be enabled to use integrated logins and a mapping must have been granted between the user profile used to log in to the machine and/or network, and a database user. Using an integrated login is more convenient for the user and permits a single security system for database and network security. Its advantages include: ♦ ♦ When connecting to a database using an integrated login, the user does not need to enter a user ID or password. If you use an integrated login, the user authentication is done by the operating system, not the database: a single system is used for database security and machine or network security. Multiple user profiles can be mapped to a single database user ID. The name and password used to login to the Windows NT machine do not have to match the database user ID and password.

♦ ♦

Caution Integrated logins offer the convenience of a single security system but there are important security implications which database administrators should be familiar with.

$ For more information about security and integrated logins, see
"Security concerns: unrestricted database access" on page 81.

77

Using integrated logins

Using integrated logins
Several steps must be implemented in order to connect successfully via an integrated login.
v To use an integrated login:

1

Enable the integrated login feature in a database by setting the value of the LOGIN_MODE database option to either Mixed or Integrated (the option is case insensitive), in place of the default value of Standard. This step requires DBA authority). Create an integrated login mapping between a user profile and an existing database user. This can be done using a SQL statement or a wizard in Sybase Central. In Sybase Central, all users with integrated login permission are shown in the Integrated Logins folder. Connect from a client application in such a way that the integrated login facility is triggered.

2

3

Each of these steps is described in the sections below.

Enabling the integrated login feature
The LOGIN_MODE database option determines whether the integrated login feature is enabled. As database options apply only to the database in which they are found, different databases can have a different integrated login setting even if they are loaded and running within the same server. The LOGIN_MODE database option accepts one of following three values (which are case insensitive). ♦ ♦ ♦
Standard This is the default setting, which does not permit integrated logins. An error occurs if an integrated login connection is attempted. Mixed

With this setting, both integrated logins and standard logins are

allowed.
Integrated With this setting, all logins to the database must be made using integrated logins.

Caution Setting the LOGIN_MODE database option to Integrated restricts connections to only those users who have been granted an integrated login mapping. Attempting to connect using a user ID and password generates an error. The only exception to this are users with DBA authority (full administrative rights).

78

Chapter 2 Connecting to a Database

Example

The following SQL statement sets the value of the LOGIN_MODE database option to Mixed, allowing both standard and integrated login connections:
SET OPTION Public.LOGIN_MODE = Mixed

Creating an integrated login
User profiles can only be mapped to an existing database user ID. When that database user ID is removed from the database, all integrated login mappings based on that database user ID are automatically removed. A user profile does not have to exist for it to be mapped to a database user ID. More than one user profile can be mapped to the same user ID. Only users with DBA authority are able to create or remove an integrated login mapping. An integrated login mapping is made either using a wizard in Sybase Central or a SQL statement.
v To map an integrated login (Sybase Central):

1 2 3

Connect to a database as a user with DBA authority. Open the Integrated Logins folder for the database and double-click Add Integrated Login. On the first page of the wizard, specify the name of the system (computer) user for whom the integrated login is to be created. Also, select the database user ID this user maps to. The wizard displays the available database users. You must select one of these. You cannot add a new database user ID.

4

Follow the remaining instructions in the wizard.

v To map an integrated login (SQL):

1 2 Example

Connect to a database with DBA authority. Execute a GRANT INTEGRATED LOGIN TO statement.

The following SQL statement allows Windows NT users fran_whitney and matthew_cobb to log in to the database as the user DBA, without having to know or provide the DBA user ID or password.
GRANT INTEGRATED LOGIN TO fran_whitney, matthew_cobb AS USER dba

79

Using integrated logins

$ For more information, see "GRANT statement" on page 540 of the
book ASA Reference.

Revoking integrated login permission
You can remove an integrated login mapping using either Sybase Central or Interactive SQL.
v To revoke an integrated login permission (Sybase Central):

1 2 3

Connect to a database with DBA authority. Open the Integrated Logins folder. In the right pane, right-click the user/group you would like to remove the integrated login permission from and choose Delete from the popup menu.

v To revoke an integrated login permission (SQL):

1 2 Example

Connect to a database with DBA authority. Execute a REVOKE INTEGRATED LOGIN FROM statement.

The following SQL statement removes integrated login permission from the Windows NT user dmelanso.
REVOKE INTEGRATED LOGIN FROM dmelanso

$ See also
♦ "GRANT statement" on page 540 of the book ASA Reference

Connecting from a client application
A client application can connect to a database using an integrated login in one of the following ways: ♦ ♦ Set the INTEGRATED parameter in the list of connection parameters to yes. Specify neither a user ID nor a password in the connection string or connection dialog. This method is available only for Embedded SQL applications, including the Adaptive Server Anywhere administration utilities.

If INTEGRATED=yes is specified in the connection string, an integrated login is attempted. If the connection attempt fails and the LOGIN_MODE database option is set to Mixed, the server attempts a standard login. 80

Chapter 2 Connecting to a Database
If an attempt to connect to a database is made without providing a user ID or password, an integrated login is attempted. The attempt succeeds or fails depending on whether the current user profile name matches an integrated login mapping in the database. Interactive SQL Examples For example, a connection attempt using the following Interactive SQL statement will succeed, providing the user has logged on with a user profile name that matches a integrated login mapping in a default database of a server:
CONNECT USING ’INTEGRATED=yes’

The following Interactive SQL statement...
CONNECT

...can connect to a database if all the following are true: ♦ ♦ ♦ ♦ A server is currently running. The default database on the current server is enabled to accept integrated login connections. An integrated login mapping has been created that matches the current user’s user profile name. If the user is prompted with a dialog box by the server for more connection information (such as occurs when using the Interactive SQL utility), the user clicks OK without providing more information.

Integrated logins via ODBC

A client application connecting to a database via ODBC can use an integrated login by including the Integrated parameter among other attributes in its Data Source configuration. Setting the attribute Integrated=yes in an ODBC data source causes database connection attempts using that DSN to attempt an integrated login. If the LOGIN_MODE database option is set to Standard, the ODBC driver prompts the user for a database user ID and password.

Security concerns: unrestricted database access
The integrated login feature works by using the login control system of Windows NT in place of the Adaptive Server Anywhere security system. Essentially, the user passes through the database security if they can log in to the machine hosting the database, and if other conditions, outlined in "Using integrated logins" on page 77, are met.

81

Using integrated logins
If the user successfully logs in to the Windows NT server as "dsmith", they can connect to the database without further proof of identification provided there is either an integrated login mapping or a default integrated login user ID. When using integrated logins, database administrators should give special consideration to the way Windows NT enforces login security in order to prevent unwanted access to the database. In particular, be aware that by default a "Guest" user profile is created and enabled when Windows NT Workstation or Server is installed.
Caution Leaving the user profile Guest enabled can permit unrestricted access to a database that is hosted by that server.

If the Guest user profile is enabled and has a blank password, any attempt to log in to the server will be successful. It is not required that a user profile exist on the server, or that the login ID provided have domain login permissions. Literally any user can log in to the server using any login ID and any password: they are logged in by default to the Guest user profile. This has important implications for connecting to a database with the integrated login feature enabled. Consider the following scenario, which assumes the Windows NT server hosting a database has a "Guest" user profile that is enabled with a blank password. ♦ An integrated login mapping exists between the user fran-whitney and the database user ID DBA. When the user fran-whitney connects to the server with her correct login ID and password, she connects to the database as DBA, a user with full administrative rights. But anyone else attempting to connect to the server as fran-whitney will successfully log in to the server regardless of the password they provide because Windows NT will default that connection attempt to the "Guest" user profile. Having successfully logged in to the server using the fran_whitney login ID, the unauthorized user successfully connects to the database as DBA using the integrated login mapping.
Disable the Guest user profile for security

The safest integrated login policy is to disable the "Guest" user profile on any Windows NT machine hosting an Adaptive Server Anywhere database. This can be done using the Windows NT User Manager utility.

82

Chapter 2 Connecting to a Database

Setting temporary public options for added security
Setting the value of the LOGIN_MODE option for a given database to Mixed or Integrated using the following SQL statement permanently enables integrated logins for that database.
SET OPTION Public.LOGIN_MODE = Mixed

If the database is shut down and restarted, the option value remains the same and integrated logins are still enabled. Changing the LOGIN_MODE option temporarily will still allow user access via integrated logins. The following statement will change the option value temporarily:
SET TEMPORARY OPTION Public.LOGIN_MODE = Mixed

If the permanent option value is Standard, the database will revert to that value when it is shut down. Setting temporary public options can be considered an additional security measure for database access since enabling integrated logins means that the database is relying on the security of the operating system on which it is running. If the database is shut down and copied to another machine (such as a user’s machine) access to the database reverts to the Adaptive Server Anywhere security model and not the security model of the operating system of the machine where the database has been copied.

$ For more information on using the SET OPTION statement see "SET
OPTION statement" on page 612 of the book ASA Reference.

Network aspects of integrated logins
If the database is located on a network server, then one of two conditions must be met for integrated logins to be used: ♦ The user profile used for the integrated login connection attempt must exist on both the local machine and the server. As well as having identical user profile names on both machines, the passwords for both user profiles must also be identical. For example, when the user jsmith attempts to connect using an integrated login to a database loaded on a network server, identical user profile names and passwords must exist on both the local machine and application server hosting the database. jsmith must be permitted to login to both the local machine and the server hosting the network server.

83

Using integrated logins
♦ If network access is controlled by a Microsoft Domain, the user attempting an integrated login must have domain permissions with the Domain Controller server and be logged in to the network. A user profile on the network server matching the user profile on the local machine is not required.

Creating a default integrated login user
A default integrated login user ID can be created so that connecting via an integrated login will be successful even if no integrated login mapping exists for the user profile currently in use. For example, if no integrated login mapping exists for the user profile name JSMITH, an integrated login connection attempt will normally fail when JSMITH is the user profile in use. However, if you create a user ID named Guest in a database, an integrated login will successfully map to the Guest user ID if no integrated login mapping explicitly identifies the user profile JSMITH. The default integrated login user permits anyone attempting an integrated login to successfully connect to a database if the database contains a user ID named Guest. The permissions and authorities granted to the newlyconnected user are determined by the authorities granted to the Guest user ID.

84

C H A P T E R

3

Client/Server Communications

About this chapter

Each network environment has its own peculiarities. This chapter describes those aspects of network communication that are relevant to the proper functioning of your database server, and provides some tips for diagnosing network communication problems. It describes how networks operate, and provides hints on running the network database server under each protocol.
Network database server only

The material in this chapter applies only to the network server. You do not need to read this chapter if you are using the personal database server. Contents
Topic Network communication concepts Real world protocol stacks Supported network protocols Using the TCP/IP protocol Using the SPX protocol Using the NetBIOS protocol Using Named Pipes Troubleshooting network communications Page 86 91 94 95 98 100 101 102

85

Network communication concepts

Network communication concepts
Applications in a local area network communicate using a set of rules and conventions called an application protocol. Each application is isolated from the lower-level details of how information gets transported across the network by lower-level protocols, which form a protocol stack. This section provides a brief description of how protocol stacks work. Hints regarding specific network issues later in this chapter assume a basic understanding of how protocol stacks operate.

The protocol stack

Application

Application level protocol

Application

Transport

Transport level proocol

Transport

Network

Network level protocol

Network

Data Link

Data link protocl

Data Link

Physical

Physical transmission

Physical

Computer A

Computer B

The figure shows the layers of a protocol stack, based on a simplification of the OSI Reference Model of network communications.

86

Chapter 3 Client/Server Communications
The OSI (Open Systems Interconnection) Reference Model, developed by the International Organization for Standardization (ISO), is a step towards international standardization of network protocols. Most current networking software and hardware conforms to some extent, but not exactly, to this model. Even though conformance is incomplete, the OSI model is a valuable aid in understanding how network communications work.

How information is passed across a network
When one network application sends information to another network application (such as the database server), the information passes down one protocol stack, across the network, and up the other protocol stack to the other application. Protocol stacks have layers The protocol stack isolates the different functions needed for reliable data transfer. Each layer of the protocol stack is connected to the layers above and below it by an interface. Each layer of a protocol stack treats information passed to it by the layer above it merely as data, labeling that data in such a way as to be identified and deciphered by the equivalent layer on the other computer. Only the physical layer is responsible for actually placing data onto the wire—all other layers provide some well-defined level of functionality, such as error detection, correction, encryption and so on. Each layer has a protocol Although actual data transmission is vertical (down one stack, up the other), each layer is programmed as if it were in direct communication with the corresponding layer on the other stack (peer-to-peer communication). The rules and conventions that govern each level of peer-to-peer communication are called a protocol for that level. There exist transport protocols, network protocols, data link protocols, and application level protocols, among others. The protocol stacks on each side of the communication must be compatible at each level for network communications to work properly. If they are not compatible, the layer on the receiving stack does not understand the information being passed to it by its corresponding layer on the sending stack. Software that manages lower levels in a protocol stack is often called a driver. The different layers of a protocol stack have the following functions:

Protocol stack compatibility

87

Network communication concepts

The physical layer
Your network adapter, or network card, and the network wiring form the physical layer for network communication. The higher layers in the protocol stacks ensure that software does not have to be aware of the details of network wiring or network adapter design.

The data link layer
The job of a data link layer is to handle the safe passing of information across the network at the level of individual sets of bits. At higher levels of the protocol stack, data is not described in terms of individual bits. It is at the data link layer that information is broken down to this elementary level. The data link layer’s interface with the network layer above it in the protocol stack commonly conforms to one of two specifications: the Network Driver Interface Specification (NDIS) developed jointly by IBM and Microsoft, and the Open Device Interface (ODI) developed by Novell. ODI and NDIS data link layers can be made compatible with each other using a translation driver.

$ For more information, see "Working with multiple protocol stacks" on
page 92.

The network layer
The network layer takes a packet of information from the transport layer above it and gets it to the corresponding network layer on the receiving protocol stack. Issues of routing are handled by the network layer. Information at a higher level is broken down into packets of a specified size (in numbers of bytes) for transmission across a network.

The transport layer
The principal task of the transport layer is to guarantee the transmission of information between applications. It accepts information directly from a network application, such as a database server, splits it up if necessary, passes the packets to the network layer and ensures that the pieces all arrive correctly at the other end, where it assembles the packets before passing them up the stack to the application layer.

88

Chapter 3 Client/Server Communications

Examples of transport protocols

Novell’s SPX, Microsoft and IBM’s NetBEUI, and Named Pipes are widelyused transport protocols. The TCP/IP suite of protocols includes more than one transport layer. NetBIOS is an interface specification to the transport layer from IBM and Microsoft that is commonly (but not necessarily) paired with the NetBEUI protocol. Adaptive Server Anywhere supports the NetBIOS interface to the transport layer. In addition, Adaptive Server Anywhere has an interface to Named Pipes for same-machine communications only. Adaptive Server Anywhere applies its own checks to the data passed between client application and server, to further ensure the integrity of data transfer.

The application layer
Database servers and client applications are typical application layers in a protocol stack, from a networking point of view. They communicate using an application-defined protocol. This protocol is internal to Adaptive Server Anywhere programs. Typical data for transmission includes a SQL query or other statement (from client application to database server) or the results of a SQL query (from database server to client application). Passing information down the protocol stack The client library and database server have an interface at the transport level (in the case of NetBIOS or Named Pipes), or at the network level, passing the information to the network communications software. The lower levels of the protocol stack are then responsible, independent of the application, for transmitting the data to the equivalent layer on the other computer. The receiving layer hands the information to Adaptive Server Anywhere on the receiving machine. The database server and the client library perform a set of checks and functions to ensure that data passed across the network arrives correctly, in a proper form.

Compatible protocol stacks
For two protocol stacks to be compatible, they must be operating the same transport layer (say NetBIOS) on each stack, and the same network protocol on each stack (say IP). If one stack employs a NetBIOS interface to the transport layer, so must the other. A client application running on a protocol stack employing NetBIOS cannot communicate with a database server using a TCP/IP protocol stack. 89

Network communication concepts
At the data link layer, ODI-based protocol stacks can be made compatible with NDIS-based protocol stacks using translation drivers, as discussed in "Working with multiple protocol stacks" on page 92.

90

Chapter 3 Client/Server Communications

Real world protocol stacks
The OSI model is close enough to current networking software and hardware to be a useful model for thinking about networks. There are inevitable complications because of the different ways in which software companies have designed their own systems. Also, there are complications when an individual computer is running more than one protocol stack, as is increasingly common.

Common protocol stacks
The TCP/IP protocol is available on all major operating systems. In addition, some widely used network software packages implement their own protocol stacks. Here are some networking software vendors together with their most common proprietary protocol stacks. ♦
Novell

Novell NetWare typically operates using an SPX transport level atop an IPX network protocol (often written as SPX/IPX). Novell’s IPX requires an ODI data link layer. The NetWare client installation installs this protocol stack on Novell NetWare client computers. Adaptive Server Anywhere has an interface directly to the IPX protocol, and does not rely on the services of the SPX layer. NetWare, IPX, and ODI are often used interchangeably when discussing network protocols.

Microsoft Microsoft Windows NT 3.5 and later comes with networking software for NetBIOS, SPX/IPX, and TCP/IP. Windows 95/98 installs SPX/IPX as default networking software, and also comes with NetBEUI software. IBM

IBM LAN Server and other IBM networking software use a NetBIOS interface to a NetBEUI transport layer on top of an NDIS data link layer. The NDIS data link layer protocol was jointly developed by Microsoft and IBM, and is employed by all IBM’s higher-level protocols.

In each case, the installed data link layer may be changed from ODI to NDIS (or vice versa) by other networking software if more than one network protocol is installed. In these cases a translation driver ensures that both ODI and NDIS data link layer interfaces are available to the higher levels of the protocol stack. Working with more than one protocol stack is discussed in more detail in the next section.

91

Real world protocol stacks

Working with multiple protocol stacks
For two network applications (such as a client application and a database server) to communicate, the client computer and the server computer must have compatible protocol stacks at each level. When each computer has a single network protocol installed, it is fairly straightforward to ensure that each is running the same stack. However, when each computer is running multiple protocols, the situation becomes more complex. At the transport and network layers, there is no problem with more than one protocol running at once; as long as there is a compatible path through the protocol stacks, the two applications can communicate. ODI and NDIS interfaces There are two widely-used interfaces between the data link layer and the network layer above it: ODI and NDIS. The data link layer communicates directly with the network adapter, so only one data link driver can be installed at a time. However, because most data link layers do not modify the information placed on the network wire, an ODI data link driver on one computer is compatible with an NDIS driver on another computer. Each network layer is written to work with one, and only one, of ODI or NDIS. However, translation drivers are available that enable network level protocols that require an NDIS (or ODI) data link interface to work with ODI (or NDIS) data link layers. Consequently, a protocol stack built on an ODI data link layer can be compatible with a protocol stack based on an NDIS data link layer as long as the upper layers are compatible. ODI and NDIS translation drivers For example, Novell provides a driver named odinsup, which enables support for NDIS network protocols on an ODI data link layer, as well as a driver named odi2ndi, which translates in the other direction. Microsoft provides an ODI to NDIS mapper called odihlp.exe with Windows 95/98. The translation drivers enable NDIS-based protocol stacks to be compatible with ODI-based protocol stacks on other computers, and to coexist on the same computer. You can think of the network adapter driver, the NDIS or ODI interface, and (if present) the translation driver as together forming the data link layer. For instance, you can configure a computer with an NDIS driver to communicate (via odi2ndi) with a Novell NetWare server using SPX/IPX on ODI drivers and, at the same time, communicate (via the NDIS driver) with a Windows NT computer using TCP/IP on an NDIS driver.

92

Chapter 3 Client/Server Communications

Troubleshooting tip

Not all translation drivers achieve complete compatibility. Be sure to get the latest available version of the driver you need. Although we provide some tips concerning network troubleshooting, the primary source of assistance in troubleshooting a particular protocol stack is the documentation for the network communications software that you install.

93

Supported network protocols

Supported network protocols
Properly configured Adaptive Server Anywhere servers run under the following networks and protocols: ♦ ♦ ♦ ♦
Windows NT and Windows 95/98

NetBIOS, TCP/IP, or SPX

protocols.
Windows CE NetWare UNIX

TCP/IP protocol.

All Novell networks using the SPX or TCP/IP protocols.

TCP/IP protocol.

Where SPX is listed, IPX can also be used, but is deprecated. Support for IPX is to be dropped in the next major release of Adaptive Server Anywhere. In addition, two protocols are provided for communication from a client application running on the same machine but built for a different operating system. ♦
Windows NT Named Pipes is used to communicate with Windows 3.x client applications from previous versions of the software, running on the same machine as the server. Named Pipes can also be used for samemachine communication between any application and the server, but is generally not recommended for this purpose. Named Pipes are not used for network communications. Windows 95/98

TCP/IP can be used for communications between a Windows 3.x client from a previous version of the software, and a Windows 95/98 database server running on the local machine or a different machine.

The client library for each platform supports the same protocols as the corresponding server. In order for Adaptive Server Anywhere to run properly, the protocol stack on the client and server computers must be compatible at each layer.

94

Chapter 3 Client/Server Communications

Using the TCP/IP protocol
TCP/IP is a suite of protocols originally implemented by the University of California at Berkeley for BSD UNIX. TCP/IP has gained widespread use with the expansion of the Internet and the World-Wide Web. Different TCP/IP implementations rely on particular data link drivers in order to work correctly. For example, TCP/IP for NetWare relies on ODI drivers. Unlike NetBEUI and SPX/IPX, the TCP/IP protocol is not associated with any specific software vendor. There are many implementations of TCP/IP available from different vendors, and many different programming interfaces to TCP. Consequently, Adaptive Server Anywhere supports only certain TCP/IP implementations on each platform. For details, see the subsections below for each platform. Because all TCP/IP implementations do implement the same protocol suite, they are all compatible. UDP is a transport layer protocol that sits on top of IP. Adaptive Server Anywhere uses UDP on top of IP to do initial server name resolution and TCP for connection and communication after that.

Using TCP/IP with Windows 95/98 and Windows NT
The TCP/IP implementation for Windows NT is written to the Winsock 2.0 standard, and that for Windows 95/98 uses the Winsock 1.1 standard. Your TCP/IP software must support this standard. Windows 95/98 and Windows NT ship with TCP/IP software that uses NDIS network drivers. If you do not have TCP/IP installed, choose TCP/IP Protocol from the Windows NT Control Panel, Network Settings. This software allows a database server for Windows NT or a client application to use Windows NT TCP/IP.

Using TCP/IP with UNIX
The UNIX database server supports TCP/IP. This enables non-UNIX clients to communicate with a UNIX database server.

95

Using the TCP/IP protocol

Tuning TCP/IP performance
Increasing the packet size may improve query response time, especially for queries transferring a large amount of data between a client and a server process. You can set the packet size using the -p parameter on the database server command line, or by setting the CommBufferSize connection parameter in your connection profile.

$ For more information, see , "–p command-line option" on page 33 of
the book ASA Reference, or "CommBufferSize connection parameter" on page 51 of the book ASA Reference.

Connecting across a firewall
There are restrictions on connections when the client application is on one side of a firewall, and the server is on the other. Firewall software filters network packets according to network port. Also, it is common to disallow UDP packets from crossing the firewall. When connecting across a firewall, you must use a set of communication parameters in the CommLinks connection parameter of your application's connection string. ♦
ClientPort Set this parameter to a range of allowed values for the client application to use. You can then configure your firewall to allow these packets across. You can use the short form CPort. HOST

♦ ♦

Set this parameter to the host name on which the database server is running. You can use the short form IP.

ServerPort

If your database server is not using the default port of 2638, you must specify the port it is using. You can use the short form Port.

Example

The following connection string fragment restricts the client application to ports 5050 through 5060, and connect to a server named myeng running on the machine at address myhost using the server port 2020. No UDP broadcast is carried out because of the DoBroadcast option.

Eng=myeng; Links=tcpip(ClientPort=5050-5060;Host=myhost;Port=2020;DoBroadcast=NONE)

$ For more information, see the following:
♦ ♦ ♦ 96 "CommLinks connection parameter" on page 52 of the book ASA Reference "ClientPort parameter" on page 65 of the book ASA Reference "ServerPort parameter" on page 70 of the book ASA Reference

Chapter 3 Client/Server Communications
♦ ♦ "Host parameter" on page 68 of the book ASA Reference "DoBroadcast parameter" on page 66 of the book ASA Reference.

Connecting on a dialup network connection
You can use connection and communications parameters to assist with connecting to a database across a dialup link. On the client side, you should specify the following communications parameters: ♦
Host parameter

You should specify the host name or IP address of the database server using the Host communication parameter. book ASA Reference.

$ For more information, see "Host parameter" on page 68 of the

DoBroadcast parameter If you specify the Host parameter, there is no need to do a broadcast search for the database server. For this reason, turn off broadcasting.

$ For more information, see "DoBroadcast parameter" on page 66 of
the book ASA Reference. ♦
MyIP parameter

You should set MyIP=NONE on the client side.

$ For more information, see "MyIP parameter" on page 69 of the
book ASA Reference. A typical CommLinks parameter may look as follows:
Links=tcpip(MyIP=NONE;DoBroadcast=NO;Host=server_ip)

97

Using the SPX protocol

Using the SPX protocol
SPX is a protocol from Novell. Adaptive Server Anywhere for NetWare, Windows NT, and Windows 95/98 can all employ the SPX protocol. This section provides some tips for using SPX under different operating systems. Connecting via SPX Some machines can use the NetWare bindery. These machines are NetWare servers or Windows NT or Windows 95/98 machine where the Client Service for NetWare is installed. A client application on one of these machines does not need to use broadcasts to connect to the server, if the server to which it is connecting is also using the bindery. Applications and servers running on machines not using the bindery must connect using either of the following: ♦
An explicit address You can specify an explicit address using the HOST communication parameter.

$ For more information, see "Host parameter" on page 68 of the
book ASA Reference. ♦
Broadcast You can broadcast over a network by specifying the DOBROADCAST communication parameter.

$ For more information, see "DoBroadcast parameter" on page 66 of
the book ASA Reference.

Using IPX with Windows NT
Windows NT 3.5 ships with IPX network software that uses NDIS network drivers. This software can be installed from the Windows NT Control Panel, Network Settings. This software allows a Windows NT database server or a client application to use Windows NT IPX running on NDIS, while also allowing access to a NetWare file server, even though the NetWare file server will generally be using an ODI driver. You must install both NWLink IPX/SPX Compatible Transport and Client Service for NetWare to use this feature. In some environments, problems have been found when the default setting (Auto-detect) has been chosen for the frame type. In this case, the frame type settings for the client and the server should be the same.

98

Chapter 3 Client/Server Communications

Using SPX with Windows 95/98
The IPX/SPX network protocol is the default network installed by Windows 95/98. If you installed Windows 95/98 without network support, you can install it later from the Control Panel, Network Settings.

99

Using the NetBIOS protocol

Using the NetBIOS protocol
NetBIOS is an interface for interprocess communications, not a protocol specification. Programs written to the NetBIOS interface should operate over a variety of protocol stacks. Protocol stacks that implement the NetBIOS interface must be compatible between client and server machines. For instance, a NetBIOS interface using SPX/IPX as the communication mechanism is incompatible with another NetBIOS implementation using NetBEUI. As Windows 95/98 and IBM networking software all use NetBIOS with NetBEUI as a standard protocol, configuration of the NetBIOS protocol stack for these environments is carried out by the network software installation. The number of connections permitted per server is limited by the setting of the Sessions parameter, and by the number of NetBIOS commands available on your machine. The number of NetBIOS commands is a machinedependent setting independent of Adaptive Server Anywhere.

$ For more information, see "Sessions parameter" on page 71 of the book
ASA Reference.

Using NetBIOS with Windows NT
Windows NT 3.5 and later ships with NetBIOS interfaces to a number of different protocol stacks (NetBEUI, NetWare IPX/SPX transport, TCP/IP) that use NDIS network drivers. To use NetBIOS, install NetBIOS Interface from the Windows NT Control Panel, Network Settings. Adaptive Server Anywhere works with any of these protocol stacks, but you must be sure to use compatible protocol stacks on the client and server sides of the communication. You can have more than one NetBIOS interface active at one time. Each interface appears to as a different LAN adapter number. Adaptive Server Anywhere can simultaneously use different LAN adapter numbers, and so can simultaneously communicate on multiple NetBIOS interface protocol stacks.

100

Chapter 3 Client/Server Communications

Using Named Pipes
Named pipes are a facility for interprocess communication. Named pipes can be used for communication between processes on the same computer or on different computers. Adaptive Server Anywhere for Windows NT uses local named pipes. This allows Windows 3.x applications from previous versions of the software running on Windows NT to communicate with a database server on the same machine. Adaptive Server Anywhere does not use named pipes for client/server communications between different machines. You do not need to install remote named pipe support for local named pipes to work.

101

Troubleshooting network communications

Troubleshooting network communications
Network software involves several different components, increasing the likelihood of problems. Although we provide some tips concerning network troubleshooting here, the primary source of assistance in network troubleshooting should be the documentation and technical support for your network communications software, as provided by your network communications software vendor.

Ensure that you are using compatible protocols
If you have more than one protocol stack installed on the client or server computer, you should ensure that the client and the database server are using the same protocol. The -x command line switch for the server selects a list of protocols for the server to use, and the CommLinks connection parameter does the same for the client application. You can use these options to ensure that each application is using the same protocol. By default, both the database server and client library use all available protocol stacks. The server supports client requests on any active protocol, and the client searches for a server on all active protocols.

$ For more information about the -x switch, see "The database server" on
page 14 of the book ASA Reference. For information about the CommLinks connection parameter, see "CommLinks connection parameter" on page 52 of the book ASA Reference.

Ensure that you have current drivers
Old network adapter drivers are a common source of communication problems. You should ensure that you have the latest version of the NDIS or ODI driver for your network adapter, as appropriate. You should be able to obtain current network adapter drivers from the manufacturer or supplier of the card. Network adapter manufacturers and suppliers make the latest versions of drivers for their cards available. Most card manufacturers have a Web site from which you can download the latest versions of NDIS and ODI drivers. You may also be able to obtain a current network adapter driver from the provider of your networking software.

102

Chapter 3 Client/Server Communications
When you download Novell client software, it has ODI drivers for some network adapters in addition to the Novell software that is used for all network adapters.

Switch off your computer between attempts
Some network adapter boards do not reset cleanly when you reboot the computer. When you are troubleshooting, it is better to turn the computer off, wait a few seconds, and then turn it back on between attempts.

Diagnose your protocol stack layer by layer
If you are having problems getting your client application to communicate with a database server, you need to ensure that the client and the database server are using compatible protocol stacks. A helpful method of isolating network communication problems is to work up the protocol stack, testing whether each level of communication is working properly. If you can connect to the server computer in any way, then the data link layer is working, regardless of whether the connection is made using the same higher-layer protocols you will be using for Adaptive Server Anywhere. For example, you may want to try to connect to a disk drive on the computer running the database server from the computer running the client application. Having verified that the data link layer is working, the next step is to verify that other applications using the same network and transport layers as Adaptive Server Anywhere are working properly.

Testing a NetBIOS protocol stack
If you are using Windows 95/98, or Windows NT, and you are using the native protocol, try using the chat or WinPopup application. This tests whether applications on the client and server computers can communicate with each other. You should ensure that the applications that come with your networking software are running properly before testing Adaptive Server Anywhere.

103

Troubleshooting network communications

Testing a TCP/IP protocol stack
If you are running under TCP/IP, there are several applications that you can use to test the compatibility of the client computer and server computer TCP/IP protocol stack. The ping utility provided with many TCP/IP packages is useful for testing the IP network layer. Using ping to test the IP layer Each IP layer has an associated address—a four-integer period-separated number (such as 191.72.109.12). Ping takes as an argument an IP-address and attempts to send a single packet to the named IP-protocol stack. First, determine if your own protocol stack is operating correctly by "pinging" yourself. If your IP-address is 191.72.109.12, you would type:
ping 191.72.109.12

at the command line prompt and wait to see if the packets are routed at all. If they are, the output will appear similar to the following:
c:> ping 191.72.109.12 Pinging 191.72.109.12 with 32 bytes of data: Reply from 191.72.109.12: bytes=32 time<.10ms TTL=32 Reply from 191.72.109.12: bytes=32 time<.10ms TTL=32 Reply from 191.72.109.12: bytes=32 time<.10ms TTL=32 ...

If this works, it means that the computer is able to route packets to itself. This is reasonable assurance that the IP layer is set up correctly. You could also ask someone else running TCP/IP for their IP address and try pinging them. You should ensure that you can ping the computer running the database server from the client computer before proceeding. Using telnet to test the TCP/IP stack To further test the TCP/IP stack you can start a server application on one computer, and a client program on the other computer, and test whether they can communicate properly. There are several applications commonly provided with TCP/IP implementations that can be used for this purpose: here we show how to use telnet to test the TCP/IP stack. 1 Start a telnet server process (or daemon) on one machine. Check with your TCP/IP software for how to do this. To start a typical command line telnet program you would type the following instruction at the command prompt:
telnetd

104

Chapter 3 Client/Server Communications
2 Start the telnet client process on the other machine, and see if you get a connection. Again, check with your TCP/IP software for how to do this. For command line programs, you would typically type the following instruction:
telnet server_name

where server_name is the name or IP address of the computer running the telnet server process. If a telnet connection is established between these two machines, the protocol stack is stable and the client and server should be able to communicate using the TCP/IP link between the two computers. If a telnet connection cannot be established, there is a problem. You should ensure that your TCP/IP protocol stack is working correctly before proceeding.

Diagnosing wiring problems
Faulty network wiring or connectors can cause problems that are difficult to track down. Try recreating problems on a similar machine with the same configuration. If a problem occurs on only one machine, it may be a wiring problem or a hardware problem. For information on detecting wiring problems under NetWare, see your Novell NetWare manuals. The Novell LANalyzer program is useful for tracking down wiring problems with Ethernet or TokenRing networks. Your NetWare authorized reseller can also supply you with the name of a Certified NetWare Engineer who can help diagnose and solve wiring problems.

A checklist of common problems
$ For more information about network communication parameters, see
"Network communications parameters" on page 65 of the book ASA Reference. The following list presents some common problems and their solutions. If you receive the message Unable to start — server not found when trying to start the client, the client cannot find the database server on the network. Check for the following problems: ♦ The network configuration parameters of your network driver on the client machine are different from those on the server machine. For example, two Ethernet adapter cards should be using a common frame type. For Novell NetWare, the frame type is set in the net.cfg file. Under Windows 95/98 and Windows NT the settings can be accessed through the Control Panel Network Settings. 105

Troubleshooting network communications
♦ Under the TCP/IP protocol, clients search for database servers by broadcasting a request. Such broadcasts will typically not pass through gateways, so any database server on a machine in another (sub)network, will not be found. If this is the case, you must supply the host name of the machine on which the server is running using the -x command-line option. This is required to connect to NetWare servers over TCP. Your network drivers are not installed properly or the network wiring is not installed properly. The network configuration parameters of your network driver are not compatible with Adaptive Server Anywhere multi-user support. See "Configuring your network adapter board" on page 106 for a description of configuration parameters that affect performance and may affect operation of the client and server. If your network communications are being carried out using TCP/IP, and you are operating under indows NT, check that your TCP/IP software conforms to the Winsock 1.1 standard. If you receive the message Unable to initialize any communication links, no link can be established. The probable cause is that your network drivers have not been installed. The server and the client try to start communication links using all available protocols unless you have specified otherwise using the -x option. Check your network documentation to find out how to install the driver you wish to use.

♦ ♦

Configuring your network adapter board
Network adapter boards have configuration settings that allow them to use different interrupt request (IRQ) levels. The network adapter board may work only when it is using the same IRQ level as another adapter board in your computer (for example, your parallel card). Performance may suffer when the network adapter board shares an IRQ level. The drivers for some adapter boards have parameters. The most important type of parameter to look out for is one that controls buffer size or number of buffers. For example, some versions of the NDIS driver for an SMC PLUS Ethernet adapter have these configuration parameters:
ReceiveBuffers = 12 ReceiveBufSize = 768

106

Chapter 3 Client/Server Communications
The default packet size for Adaptive Server Anywhere is 1024 bytes. The maximum buffer size used by the adapter board should be greater than this to allow for protocol information in the packet. The computer running the database server might need more than the default number of buffers used by a driver.

107

Troubleshooting network communications

108

P A R T

TW O

Working with Databases

This part of the manual describes the mechanics of carrying out common tasks with Adaptive Server Anywhere.

109

110

C H A P T E R

4

Working with Database Objects

About this chapter Contents

This chapter describes the mechanics of creating, altering, and deleting database objects such as tables, views, and indexes.
Topic Introduction Working with databases Working with tables Working with views Working with indexes Page 112 115 124 138 145

111

Introduction

Introduction
With the Adaptive Server Anywhere tools, you can create a database file to hold your data. Once this file is created, you can begin managing the database. For example, you can add database objects, such as tables or users, and you can set overall database properties. This chapter describes how to create a database and the objects within it. It includes procedures for Sybase Central, Interactive SQL, and command-line utilities. If you want more conceptual information before you begin, see the following chapters: ♦ ♦ ♦ ♦ "Designing Your Database" on page 333 "Ensuring Data Integrity" on page 357 "About Sybase Central" on page 36 of the book Introducing SQL Anywhere Studio "Using Interactive SQL" on page 161 of the book Getting Started with ASA

The SQL statements for carrying out the tasks in this chapter are called the data definition language (DDL). The definitions of the database objects form the database schema: you can think of the schema as an empty database.

$ Procedures and triggers are also database objects, but they are
discussed in "Using Procedures, Triggers, and Batches" on page 435. Chapter contents This chapter contains the following material: ♦ ♦ ♦ Questions and answers An introduction to working with database objects (this section) A description of how to create and work with the database itself A description of how to create and alter tables, views, and indexes
Consider reading... "Creating a database" on page 115 and "Erasing a database" on page 118 "Disconnecting from a database" on page 119 "Setting properties for database objects" on page 120 "Setting database options" on page 120 "Setting a consolidated database" on

To answer the question... How do I create or erase a database? How do I disconnect from a database? How do I set the properties for any database object? How do I set database options? How do I set the consolidated database?

112

Chapter 4 Working with Database Objects
To answer the question... How do I show system objects in Sybase Central? How do I keep track of the SQL Statements that Sybase Central automatically generates as I work with it? How do I add jConnect meta-data support for an existing database? What is the Table Editor, and what can I do with it? What are system tables, and how can I work with them? How do I create or delete tables? How do I alter existing tables? Consider reading... page 121 "Showing system objects in a database" on page 121 "Logging SQL statements as you work with a database" on page 122

"Installing the jConnect meta-data support to an existing database" on page 123 "Using the Sybase Central Table Editor" on page 124 "Showing system tables" on page 136 "Creating tables" on page 126 and "Deleting tables" on page 130 "Altering tables" on page 128. This section does not describe how to change properties or permissions, but it does provide cross-references to the appropriate locations. "Browsing the information in tables" on page 131 and "Browsing the information in views" on page 144 "Managing primary keys" on page 131 "Managing foreign keys" on page 133 "Copying tables or columns within/between databases" on page 136 "Creating views" on page 138 and "Deleting views" on page 143

If I’m working in Sybase Central, how do I browse the information in a table or view? What are primary keys, and what can I do with them? What are foreign keys, and what can I do with them? How do I copy tables or columns?

How do I create or delete views?

113

Introduction
To answer the question... How can I use views? Consider reading... "Using views" on page 140 and "Using the WITH CHECK OPTION clause" on page 140 "Views in the system tables" on page 144 "Modifying views" on page 142 "Creating indexes" on page 146 and "Deleting indexes" on page 147 "Validating indexes" on page 146

How can I work with views in the system tables? How do I modify existing views? How do I create or delete indexes? How do I validate an existing index?

114

Chapter 4 Working with Database Objects

Working with databases
This section describes how to create and work with a database. As you read this section, keep in mind the following simple concepts: ♦ The databases that you can create (called relational databases) are a collection of tables, related by primary and foreign keys. These tables hold the information in a database, and the tables and keys together define the structure of the database. A database may be stored in one or more database files, on one or more devices. A database file also contains the system tables, which hold the schema definition as you build your database.

Creating a database
Adaptive Server Anywhere provides a number of ways to create a database: in Sybase Central, in Interactive SQL, and with the command line. Creating a database is also called initializing it. Once the database is created, you can connect to it and build the tables and other objects that you need in the database. Transaction log When you create a database, you must decide where to place the transaction log. This log stores all changes made to a database, in the order in which they are made. In the event of a media failure on a database file, the transaction log is essential for database recovery. It also makes your work more efficient. By default, it is placed in the same directory as the database file, but this is not recommended for production use.

$ For information on placing the transaction log, see "Configuring your
database for data protection" on page 663. Database file compatibility An Adaptive Server Anywhere database is an operating system file. It can be copied to other locations just like any other file is copied. Database files are compatible among all operating systems, except where file system file size limitations or Adaptive Server Anywhere support for large files apply. A database created from any operating system can be used from another operating system by copying the database file(s). Similarly, a database created with a personal server can be used with a network server. Adaptive Server Anywhere servers can manage databases created with earlier versions of the software, but old servers cannot manage newer databases.

$ For more information about limitations, see "Size and number
limitations" on page 958 of the book ASA Reference. 115

Working with databases
Some application design systems, such as Sybase PowerBuilder, contain facilities for creating database objects. These tools construct SQL statements that are submitted to the server, typically through its ODBC interface. If you are using one of these tools, you do not need to construct SQL statements to create tables, assign permissions, and so on. This chapter describes the SQL statements for defining database objects. You can use these statements directly if you are building your database from an interactive SQL tool, such as Interactive SQL. Even if you are using an application design tool, you may want to use SQL statements to add features to the database if they are not supported by the design tool. For more advanced use, database design tools such as Sybase PowerDesigner provide a more thorough and reliable approach to developing well-designed databases.

Using other applications to create databases

$ For more information about database design, see "Designing Your
Database" on page 333.

Creating databases (Sybase Central)
You can create a database in Sybase Central using the Create Database utility. After you have created a database, it appears under its server in the Sybase Central object tree. Creating databases for Windows CE Sybase Central has features to make database creation easy for Windows CE databases. If you have Windows CE services installed on your Windows 95 or Windows NT desktop, you have the option to create a Windows CE database when you create a database from Sybase Central. Sybase Central enforces the requirements for Windows CE databases, and optionally copies the resulting database file to your Windows CE machine.
v To create a new database (Sybase Central):

1 2

Choose Tools®Adaptive Server Anywhere®Create Database. Follow the instructions of the wizard.

v To create a new database based on a current connection:

1 2 3 4

Connect to a database. Open the Utilities folder (located within the server folder). In the right pane, double-click Create Database. Follow the instructions of the wizard.

$ For more information, see "Creating databases (SQL)" on page 117,
and "Creating databases (command line)" on page 117. 116

Chapter 4 Working with Database Objects

Creating databases (SQL)
In Interactive SQL, you can use the CREATE DATABASE statement to create databases. You need to connect to an existing database before you can use this statement.
v To create a new database (SQL):

1 2

Connect to an existing database. Execute a CREATE DATABASE statement.

$ For more information, see "CREATE DATABASE statement" on
page 427 of the book ASA Reference. Example Create a database file in the c:\temp directory with the database name
temp.db.
CREATE DATABASE ’c:\\temp\\temp.db’

The directory path is relative to the database server. You set the permissions required to execute this statement on the server command line, using the -gu command-line option. The default setting requires DBA authority. The backslash is an escape character in SQL, and must be doubled. For more information, see "Strings" on page 224 of the book ASA Reference.

Creating databases (command line)
You can create a database from a command line with the dbinit utility. With this utility, you can include command-line parameters to specify different options for the database.
v To create a new database (command line):

1 2 Example

Open a command prompt. From a command line, run the dbinit utility. Include any necessary parameters.

Create a database called company.db with a 4kb page size:
dbinit –p 4096 company.db

$ For more information, see "The Initialization utility" on page 98 of the
book ASA Reference.

117

Working with databases

Erasing a database
Erasing a database deletes all tables and data from disk, including the transaction log that records alterations to the database. All database files are read-only to prevent accidental modification or deletion of the database files. In Sybase Central, you can erase a database using the Erase Database utility. You need to connect to a database to access this utility, but the Erase Database wizard lets you specify any database for erasing. In order to erase a non-running database, the database server must be running. In Interactive SQL, you can erase a database using the DROP DATABASE statement. Required permissions can be set using the database server -gu command-line option. The default setting is to require DBA authority. You can also erase a database from a command line with the dberase utility. The database to be erased must not be running when this utility is used.
v To erase a database (Sybase Central):

1 2 3

Open the Utilities folder. In the right pane, double-click Erase Database. Follow the instructions of the wizard.

v To erase a database (SQL):

♦ Example

Execute a DROP DATABASE statement.

Erase the database temp.db, in the C:\temp directory.
DROP DATABASE ’c:\temp\temp.db’

v To erase a database (command line):

♦ Example

From a command line, run the dberase utility.

Erase the database company.db and its transaction log:
dberase company.db

A message box asks you to confirm that you really want to erase the files. To erase the files, type y and press ENTER.

$ For more information, see "DROP DATABASE statement" on
page 507 of the book ASA Reference, and "The Erase utility" on page 94 of the book ASA Reference.

118

Chapter 4 Working with Database Objects

Disconnecting from a database
When you are finished working with a database, you can disconnect from it. Adaptive Server Anywhere also gives you the ability to disconnect other users from a given database; for more information about doing this in Sybase Central, see "Managing connected users" on page 752. You can obtain the connection-id for a user by using the connection_property function to request the connection number. The following statement returns the connection ID of the current connection:
SELECT connection_property( ’number’ )

v To disconnect yourself from a database (Sybase Central):

1 2 3

Open the desired server. Select the desired database. On the toolbar, click the Disconnect button.

v To disconnect yourself from a database (SQL):

♦ Example 1

Execute a DISCONNECT statement.

The following statement shows how to use DISCONNECT from Interactive SQL to disconnect all connections:
DISCONNECT ALL

Example 2

The following statement shows how to use DISCONNECT in Embedded SQL:
EXEC SQL DISCONNECT :conn_name

v To disconnect other users from a database (SQL):

1 2 Example

Connect to an existing database with DBA authority. Execute a DROP CONNECTION statement.

The following statement drops the connection with ID number 4.
DROP CONNECTION 4

$ For more information, see "DISCONNECT statement" on page 504 of
the book ASA Reference, and "DROP CONNECTION statement" on page 508 of the book ASA Reference.

119

Working with databases

Setting properties for database objects
Most database objects (including the database itself) have properties that you can either view or set. Some properties are non-configurable and reflect the settings chosen when you created the database or object. Other properties are configurable. The best way to view and set properties is to use the property sheets in Sybase Central. If you are not using Sybase Central, properties can be specified when you create the object with a CREATE statement. If the object already exists, you can modify options with a SET OPTION statement.
v To view and edit the properties of a database object (Sybase Central):

1 2 3

In the Sybase Central object tree, open the folder or container in which the object resides. Right-click the object and choose Properties from the popup menu. Edit the desired properties.

$ For more information, see "Property Sheet Descriptions" on page 1061

Setting database options
Database options are configurable settings that change the way the database behaves or performs. In Sybase Central, all of these options are grouped together in the Set Options dialog. In Interactive SQL, you can specify an option in a SET OPTION statement.
v To set options for a database (Sybase Central):

1 2 3

Open the desired server. Right-click the desired database and choose Set Options from the popup menu. Edit the desired values.

v To set the options for a database (SQL):

Specify the desired properties within a SET OPTION statement.

120

Chapter 4 Working with Database Objects

Tips

With the Set Options dialog, you can also set database options for specific users and groups. When you set options for the database itself, you are actually setting options for the PUBLIC group in that database, because all users and groups inherit option settings from PUBLIC.

$ For more information, see "Set Options dialog" on page 1036, and
"Database Options" on page 155 of the book ASA Reference.

Setting a consolidated database
In Sybase Central, you can set the consolidated database. For SQL Remote replication, the consolidated database is the one that serves as the "master" database in the replication setup. The consolidated database contains all of the data to be replicated, while its remote databases may only contain their own subsets of the data. In case of conflict or discrepancy, the consolidated database is considered to have the primary copy of all data.
v To set a consolidated database (Sybase Central):

1 2 3 4 5

Open the desired server. Right-click the desired database and choose Properties from the popup menu. Click the SQL Remote tab. Click the Change button beside the Consolidated Database text box. Configure the desired settings.

$ For more information, see "Consolidated and remote databases" on
page 5 of the book Replication and Synchronization Guide.

Showing system objects in a database
In a database, a table, view, stored procedures, or domain is a system object. System tables store information about the database itself, while system views, procedures, and domains largely support Sybase Transact-SQL compatibility.

121

Working with databases
In Interactive SQL, you cannot show a list of all system objects, but you can browse the contents of a system table; for more information, see "Showing system tables" on page 136.
v To show system objects in a database (Sybase Central):

1 2 3

Open the desired server. Right-click the desired connected database and choose Filter Objects by Owner. Enable SYS and dbo, and click OK. The system tables, system views, system procedures, and system domains appear in their respective folders (for example, system tables appear alongside normal tables in the Tables folder).

$ For more information, see "System Tables" on page 991 of the book
ASA Reference.

Logging SQL statements as you work with a database
As you work with a database in Sybase Central, the application automatically generates SQL statements depending on your actions. You can keep track of these statements either in a separate window or in a specified file. When you work with Interactive SQL, you can also log statements that you execute; for more information, see "Logging commands" on page 172 of the book Getting Started with ASA.
v To log SQL statements generated by Sybase Central:

1 2

Right-click the database and choose Log SQL Statements from the popup menu. In the resulting dialog, specify the desired settings.

$ For more information, see "Log SQL Statements dialog" on page 1037

Starting a database without connecting
With both Sybase Central and Interactive SQL, you can start a database without connecting to it.

122

Chapter 4 Working with Database Objects
v To start a database on a server without connecting (Sybase Central):

1 2

Right-click the desired server and choose Start Database from the popup menu. In the Start a Database dialog, enter the desired values. The database appears under the server as a disconnected database.

v To start a database on a server without connecting (SQL):

1 2 Example

Start Interactive SQL. Execute a START DATABASE statement.

Start the database file c:\asa7\sample_2.db as sam2 on the server named sample.
START DATABASE ’c:\asa7\sample_2.db’ AS sam2 ON sample

$ For more information, see "START DATABASE statement" on
page 620 of the book ASA Reference.

Installing the jConnect meta-data support to an existing database
If a database was created without the jConnect meta-data support, you can use Sybase Central to install it at a later date.
v To add jConnect meta-data support to an existing database (Sybase Central):

1 2 3

Open the server for the database. Right-click the database and choose Re-install jConnect Meta-data Support from the popup menu. Follow the instructions of the wizard.

123

Working with tables

Working with tables
When the database is initialized, the only tables in the database are the system tables, which hold the database schema. This section describes how to create, alter, and delete tables from a database. You can execute the examples in Interactive SQL, but the SQL statements are independent of the administration tool you use. To make it easier for you to re-create the database schema when necessary, create command files to define the tables in your database. The command files should contain the CREATE TABLE and ALTER TABLE statements.

Using the Sybase Central Table Editor
The Table Editor is a tool that you can access through Sybase Central. It provides a quick way of creating and editing tables and their columns. With the Table Editor, you can create, edit, and delete columns. You can also add and remove columns in the primary key.
v To access the Table Editor for creating a new table:

1 2

Open the Tables folder. In the right pane, double-click Add Table.

v To access the Table Editor for editing an existing table:

1 2 Table Editor toolbar

Open the Tables folder. Right-click the table and choose Edit Columns from the popup menu.

Once you have opened the Table Editor, a toolbar (shown below) provides you with the fields and buttons for common commands.

124

Chapter 4 Working with Database Objects

The first half of this toolbar shows the name of the current table and its owner (or creator). For a new table, you can specify new settings in both of these fields. For an existing table, you can type a new name but you cannot change the owner. With the buttons on the second half of the toolbar, you can: ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ Add a new column. It appears at the bottom of the list of existing columns. Delete selected columns View the Column Properties dialog for the selected column View the Advanced Table Properties for the entire table View and change the Table Editor options Add Java classes to the selected column’s data types Save the table but keep the Table Editor open Save the table and close the Table Editor in a single step

As an easy reminder of what these buttons do, you can hold your cursor over each button to see a popup description.

$ For more information, see "Column properties" on page 1075.
Using the Advanced Table Properties dialog
In the Table Editor, you can use the Advanced Table Properties dialog to set or inspect a table’s type or to type a comment for the table.
v To view or set advanced table properties:

1 2

Open the Table Editor. On the toolbar, click the Advanced Table Properties button. 125

Working with tables
3 Dialog components ♦ Edit the desired values.
Base table Designates this table as a base table (one that permanently holds the data until you delete it). You cannot change this setting for existing tables; you can only set the table type when you create a new table.

on DB space Lets you select the database space used by the table. This option is only available if you create a new table as a base table.

Global temporary table Designates this table as a global temporary table (one that holds data for a single connection only). You cannot change this setting for existing tables; you can only set the table type when you create a new table.

♦ ♦ ♦

ON COMMIT Delete rows Sets the global temporary table to delete its rows when a COMMIT is executed. ON COMMIT Preserve rows Sets the global temporary table to preserve its rows when a COMMIT is executed.

Comment Provides a place for you to type a comment (text description) of this object. For example, you could use this area to describe the object’s purpose in the system.

Tip

The table type and comment are also shown in the table's property sheet.

$ For more information, see "Property Sheet Descriptions" on
page 1061"Designing Your Database" on page 333

Creating tables
When a database is first created, the only tables in the database are the system tables, which hold the database schema. You can then create new tables to hold your actual data, either with SQL statements in Interactive SQL or with Sybase Central. There are two types of tables that you can create: ♦
Base table A table that holds persistent data. The table and its data continue to exist until you explicitly delete the data or drop the table. It is called a base table to distinguish it from temporary tables and from views.

126

Chapter 4 Working with Database Objects

Temporary table

Data in a temporary table is held for a single connection only. Global temporary table definitions (but not data) are kept in the database until dropped. Local temporary table definitions and data exist for the duration of a single connection only.

Tables consist of rows and columns. Each column carries a particular kind of information, such as a phone number or a name, while each row specifies a particular entry.
v To create a table (Sybase Central):

1 2 3 4

Connect to the database. Open the Tables folder. In the right pane, double-click Add Table. In the Table Editor: ♦ ♦ ♦ ♦ Enter a name for the new table. Select an owner for the table. Create columns using the Add Column button on the toolbar. Specify column properties.

5

Save the table and close the Table Editor when finished.

v To create a table (SQL):

1 2 Example

Connect to the database with DBA authority. Execute a CREATE TABLE statement.

The following statement creates a new table to describe qualifications of employees within a company. The table has columns to hold an identifying number, a name, and a type (technical or administrative) for each skill.
CREATE TABLE skill ( skill_id INTEGER NOT NULL, skill_name CHAR( 20 ) NOT NULL, skill_type CHAR( 20 ) NOT NULL )

$ For more information, see "CREATE TABLE statement" on page 466
of the book ASA Reference, and"Using the Sybase Central Table Editor" on page 124.

127

Working with tables

Altering tables
This section describes how to change the structure or column definitions of a table. For example, you can add columns, change various column attributes, or delete columns entirely. In Sybase Central, you can perform these tasks using the buttons on the Table Editor toolbar. In Interactive SQL, you can perform these tasks with the ALTER TABLE statement. If you are working with Sybase Central, you can also manage columns (add or remove them from the primary key, change their properties, or delete them) by working with menu commands when you have a column selected in the Columns folder.

$ For information on altering database object properties, see "Setting
properties for database objects" on page 120.

$ For information on granting and revoking table permissions, see
"Granting permissions on tables" on page 743 and "Revoking user permissions" on page 750.

Altering tables (Sybase Central)
You can alter tables in Sybase Central using the Table Editor. For example, you can add or delete columns, change column definitions, or change table or column properties.
v To alter an existing table (Sybase Central):

1 2 3 4

Connect to the database. Open the Tables folder. Right-click the table you want to alter and choose Edit Columns from the popup menu. In the Table Editor, make the necessary changes.
Tips

You can also add columns by opening a table’s Columns folder and double-clicking Add Column. You can also delete columns by opening a table’s Columns folder, rightclicking the column, and choosing Delete from the popup menu.

128

Chapter 4 Working with Database Objects

$ For more information, see "Using the Sybase Central Table Editor" on
page 124, and "ALTER TABLE statement" on page 392 of the book ASA Reference.

Altering tables (SQL)
You can alter tables in Interactive SQL using the ALTER TABLE statement.
v To alter an existing table (SQL):

1 2 Examples

Connect to the database with DBA authority. Execute an ALTER TABLE statement.

The following command adds a column to the skill table to allow space for an optional description of the skill:
ALTER TABLE skill ADD skill_description CHAR( 254 )

This statement adds a column called skill_description that holds up to a few sentences describing the skill. You can also modify column attributes with the ALTER TABLE statement. The following statement shortens the skill_description column of the sample database from a maximum of 254 characters to a maximum of 80:
ALTER TABLE skill MODIFY skill_description CHAR( 80 )

Any current entries that are longer than 80 characters are trimmed to conform to the 80-character limit, and a warning appears. The following statement changes the name of the skill_type column to
classification:
ALTER TABLE skill RENAME skill_type TO classification

The following statement deletes the classification column.
ALTER TABLE skill DROP classification

The following statement changes the name of the entire table:
ALTER TABLE skill RENAME qualification

129

Working with tables
These examples show how to change the structure of the database. The ALTER TABLE statement can change just about anything pertaining to a table—you can use it to add or delete foreign keys, change columns from one type to another, and so on. In all these cases, once you make the change, stored procedures, views and any other item referring to this column will no longer work.

$ For more information, see "ALTER TABLE statement" on page 392 of
the book ASA Reference, and "Ensuring Data Integrity" on page 357.

Deleting tables
This section describes how to delete tables from a database. You can use either Sybase Central or Interactive SQL to perform this task. In Interactive SQL deleting a table is also called dropping it. You cannot delete a table that is being used as an article in a SQL Remote publication. If you try to do this in Sybase Central, an error appears.
v To delete a table (Sybase Central):

1 2 3

Connect to the database. Open the Tables folder for that database. Right-click the table and choose Delete from the popup menu.

v To delete a table (SQL):

1 2 Example

Connect to the database with DBA authority. Execute a DROP TABLE statement.

The following DROP TABLE command deletes all the records in the skill table and then removes the definition of the skill table from the database
DROP TABLE skill

Like the CREATE statement, the DROP statement automatically executes a COMMIT statement before and after dropping the table. This makes permanent all changes to the database since the last COMMIT or ROLLBACK. The drop statement also drops all indexes on the table.

$ For more information, see "DROP statement" on page 505 of the book
ASA Reference.

130

Chapter 4 Working with Database Objects

Browsing the information in tables
To browse the data held within the tables of a database, you can use the Interactive SQL utility. This utility lets you execute queries to identity the exact data you want to view. For more information about using these queries, see "Queries: Selecting Data from a Table" on page 149. If you are working in Sybase Central, you can right-click a table and choose View Data from the popup menu. This command opens Interactive SQL with the table contents showing in the Results pane.

Managing primary keys
This section describes how to create and edit primary keys in your database. You can use either Sybase Central or Interactive SQL to perform these tasks. The primary key is a unique identifier that is comprised of a column or combination of columns with values that do not change over the life of the data in the row. Because uniqueness is essential to good database design, it is best to specify a primary key when you define the table.
Column order in multi-column primary keys

Primary key column order is determined by the order of the columns during table creation. It is not based on the order of the columns as specified in the primary key declaration.

Managing primary keys (Sybase Central)
In Sybase Central, the primary key of a table is shown in several places: ♦ ♦ ♦ On the Columns tab of the table’s property sheet. In the Columns folder of the table. In the Table Editor.

The primary key columns have special icons to distinguish them from nonkey columns. The lists in both the table property sheet and the Columns folder show the primary-key columns (along with the non-key columns) in the order that they were created in the database. This may differ from the actual ordering of columns in the primary key.
v To create and edit the primary key using a property sheet:

1 2

Open the Tables folder. Right-click the table and choose Properties from the popup menu. 131

Working with tables
3 4 Click the Columns tab of the property sheet. Use the buttons to change the primary key.

v To create and edit the primary key using the Columns folder:

1 2 3

Open the Tables folder and double-click a table. Open the Columns folder for that table and right-click a column. From the popup menu, do one of the following: ♦ ♦ Choose Add to Primary Key if the column is not yet part of the primary key and you want to add it. Choose Remove From Primary Key if the column is part of the primary key and you want to remove it.

v To create and edit the primary key using the Table Editor:

1 2 3

Open the Tables folder. Right-click a table and choose Edit Columns from the popup menu. In the Table Editor, click the icons in the Key fields (at the far left of the Table Editor) to add a column to the primary key or remove it from the key.

$ For more information, see "Managing foreign keys" on page 133.
Managing primary keys (SQL)
You can create and modify the primary key in Interactive SQL using the CREATE TABLE and ALTER TABLE statements. These statements let you set many table attributes, including column constraints and checks. Columns in the primary key cannot contain NULL values. You must specify NOT NULL on the column in the primary key.
v To modify the primary key of an existing table (SQL):

1 2 Example 1

Connect to the database with DBA authority. Execute a ALTER TABLE statement.

The following statement creates the same skill table as before, except that it adds a primary key:

132

Chapter 4 Working with Database Objects
CREATE TABLE skill ( skill_id INTEGER NOT NULL, skill_name CHAR( 20 ) NOT NULL, skill_type CHAR( 20 ) NOT NULL, primary key( skill_id ) )

The primary key values must be unique for each row in the table which, in this case, means that you cannot have more than one row with a given skill_id. Each row in a table is uniquely identified by its primary key. Example 2 The following statement adds the columns skill_id and skill_type to the primary key for the skill table:
ALTER TABLE skill ( ADD PRIMARY KEY ( "skill_id", "skill_type" ) )

If a PRIMARY KEY clause is specified in an ALTER TABLE statement, the table must not already have a primary key that was created by the CREATE TABLE statement or another ALTER TABLE statement. Example 3 The following statement removes all columns from the primary key for the skill table. Before you delete a primary key, make sure you are aware of the consequences in your database.
ALTER TABLE skill DELETE PRIMARY KEY

$ For more information, see "ALTER TABLE statement" on page 392 of
the book ASA Reference, and "Managing primary keys (Sybase Central)" on page 131.

Managing foreign keys
This section describes how to create and edit foreign keys in your database. You can use either Sybase Central or Interactive SQL to perform these tasks. Foreign keys are used to relate values in a child table (or foreign table) to those in a parent table (or primary table). A table may have multiple foreign keys that refer to multiple parent tables linking various types of information.

Managing foreign keys (Sybase Central)
In Sybase Central, the foreign key of a table is shown in the Foreign Keys folder (located within the table container). You cannot create a foreign key in a table if the table contains values for the foreign columns that can’t be matched to values in the primary table’s primary key. 133

Working with tables
After you have created a foreign key, you can keep track of them in each table’s Referenced By folder; this folder shows any foreign tables that reference the currently selected table.
v To create a new foreign key in a given table (Sybase Central):

1 2 3 4

In the Tables folder, open a table. Open the Foreign Keys folder for that table. In the right panel, double-click Add Foreign Key. Follow the instructions of the wizard.

v To delete a foreign key (Sybase Central):

1 2 3

In the Tables folder, open a table. Open the Foreign Keys folder for that table. Right-click the foreign key you want to delete and choose Delete from the popup menu.

v To show which tables have foreign keys that reference a given table (Sybase Central):

1 2

Open the desired table. Open the Referenced By folder.
Tips

When you create a foreign key using the wizard, you can set properties for the foreign key. To set or change properties after the foreign key is created, right-click the foreign key and choose Properties from the popup menu. You can view the properties of a referencing table by right-clicking the table and choosing Properties from the popup menu.

$ For more information, see "Table properties" on page 1072.
Managing foreign keys (SQL)
You can create and modify the foreign key in Interactive SQL using the CREATE TABLE and ALTER TABLE statements. These statements let you set many table attributes, including column constraints and checks. A table can only have one primary key defined, but it may have as many foreign keys as necessary. 134

Chapter 4 Working with Database Objects
v To modify the foreign key of an existing table (SQL):

1 2 Example 1

Connect to the database with DBA authority. Execute a ALTER TABLE statement.

You can create a table named emp_skill, which holds a description of each employee’s skill level for each skill in which they are qualified, as follows:

CREATE TABLE emp_skill( emp_id INTEGER NOT NULL, skill_id INTEGER NOT NULL, "skill level" INTEGER NOT NULL, PRIMARY KEY( emp_id, skill_id ), FOREIGN KEY REFERENCES employee, FOREIGN KEY REFERENCES skill )

The emp_skill table definition has a primary key that consists of two columns: the emp_id column and the skill_id column. An employee may have more than one skill, and so appear in several rows, and several employees may possess a given skill, so that the skill_id may appear several times. However, there may be no more than one entry for a given employee and skill combination. The emp_skill table also has two foreign keys. The foreign key entries indicate that the emp_id column must contain a valid employee number from the employee table, and that the skill_id must contain a valid entry from the skill table. Example 2 You can add a foreign key called "foreignkey" to the existing table skill and reference this foreign key to the primary key in the table contact, as follows:
ALTER TABLE skill ADD FOREIGN KEY "foreignkey" ("skill_id") REFERENCES "DBA"."contact" ("id")

This example creates a relationship between the skill_id column of the table skill (the foreign table) and the id column of the table contact (the primary table). The "DBA" signifies the owner of the table contact. Example 3 You can specify properties for the foreign key as you create it. For example, the following statement creates the same foreign key as in Example 2, but it defines the foreign as NOT NULL along with restrictions for when you update or delete.
ALTER TABLE skill ADD NOT NULL FOREIGN KEY "foreignkey" ("skill_id") REFERENCES "DBA"."contact" ("id") ON UPDATE RESTRICT ON DELETE RESTRICT

135

Working with tables
In Sybase Central, you can also specify properties in the foreign key creation wizard or on the foreign key’s property sheet.

$ For more information, see "ALTER TABLE statement" on page 392 of
the book ASA Reference, and "Managing foreign keys (Sybase Central)" on page 133.

Copying tables or columns within/between databases
With Sybase Central, you can copy existing tables or columns and insert them into another location in the same database or into a completely different database.

$ If you are not using Sybase Central, see one of the following locations:
♦ ♦ To insert SELECT statement results into a given location, see "SELECT statement" on page 601 of the book ASA Reference. To insert a row or selection of rows from elsewhere in the database into a table, see "INSERT statement" on page 554 of the book ASA Reference.

Showing system tables
In a database, a table, view, stored procedure, or domain is a system object. System tables store information about the database itself, while system views, procedures, and domains largely support Sybase Transact-SQL compatibility. All the information about tables in a database appears in the system tables. The information is distributed among several tables.
v To show system tables (Sybase Central):

1 2 3

Open the desired server. Right-click the desired connected database and choose Filter Objects by Owner from the popup menu. Select the check box beside SYS and click OK. The system tables, system views, system procedures, and system domains appear in their respective folders (for example, system tables appear alongside normal tables in the Tables folder).

v To browse system tables (SQL):

1 136

Connect to a database.

Chapter 4 Working with Database Objects
2 Example Execute a SELECT statement, specifying the system table you want to browse. The system tables are owned by the SYS user ID.

Show the contents of the table sys.systable in the Results pane.
SELECT * FROM SYS.SYSTABLE

$ For more information, see "System Tables" on page 991 of the book
ASA Reference.

137

Working with views

Working with views
Views are computed tables. You can use views to show database users exactly the information you want to present, in a format you can control. Similarities between views and base tables Views are similar to the permanent tables of the database (a permanent table is also called a base table) in many ways: ♦ ♦ ♦ ♦ Differences between views and permanent tables You can assign access permissions to views just as to base tables. You can perform SELECT queries on views. You can perform UPDATE, INSERT, and DELETE operations on some views. You can create views based on other views.

There are some differences between views and permanent tables: ♦ ♦ ♦ ♦ You cannot create indexes on views. You cannot perform UPDATE, INSERT, and DELETE operations on all views. You cannot assign integrity constraints and keys to views. Views refer to the information in base tables, but do not hold copies of that information. Views are recomputed each time you invoke them.

Benefits of tailoring access

Views let you tailor access to data in the database. Tailoring access serves several purposes: ♦ ♦ ♦
Improved security

By allowing access to only the information that is

relevant.
Improved usability

By presenting users and application developers with data in a more easily understood form than in the base tables. By centralizing in the database the definition

Improved consistency

of common queries.

Creating views
When you browse data, a SELECT statement operates on one or more tables and produces a result set that is also a table. Just like a base table, a result set from a SELECT query has columns and rows. A view gives a name to a particular query, and holds the definition in the database system tables.

138

Chapter 4 Working with Database Objects
Suppose you frequently need to list the number of employees in each department. You can get this list with the following statement:
SELECT dept_ID, count(*) FROM employee GROUP BY dept_ID

You can create a view containing the results of this statement using either Sybase Central or Interactive SQL.
v To create a new view (Sybase Central):

1 2 3 4 5 6

Connect to a database. Open the Views folder for that database. In the right pane, double-click Add View (Wizard). Follow the instructions in the wizard. When you’re finished, the Code Editor automatically opens. Complete the code by entering the table and the columns you want to use. For the example above, enter employee and dept_ID. From the File menu of the Code Editor, choose Save/Execute in Database. New views appear in the Views folder.

v To create a new view (SQL):

1 2 Example

Connect to a database. Execute a CREATE VIEW statement.

Create a view called DepartmentSize that contains the results of the SELECT statement given at the beginning of this section:
CREATE VIEW DepartmentSize AS SELECT dept_ID, count(*) FROM employee GROUP BY dept_ID

Since the information in a view is not stored separately in the database, referring to the view executes the associated SELECT statement to retrieve the appropriate data. On one hand, this is good because it means that if someone modifies the employee table, the information in the DepartmentSize view is automatically brought up to date. On the other hand, complicated SELECT statements may increase the amount of time SQL requires to find the correct information every time you use the view.

139

Working with views

$ For more information, see "CREATE VIEW statement" on page 482 of
the book ASA Reference.

Using views
Restrictions on SELECT statements There are some restrictions on the SELECT statements you can use as views. In particular, you cannot use an ORDER BY clause in the SELECT query. A characteristic of relational tables is that there is no significance to the ordering of the rows or columns, and using an ORDER BY clause would impose an order on the rows of the view. You can use the GROUP BY clause, subqueries, and joins in view definitions. To develop a view, tune the SELECT query by itself until it provides exactly the results you need in the format you want. Once you have the SELECT query just right, you can add a phrase in front of the query to create the view. For example,
CREATE VIEW viewname AS

Updating views

UPDATE, INSERT, and DELETE statements are allowed on some views, but not on others, depending on its associated SELECT statement. You cannot update views containing aggregate functions, such as COUNT(*). Nor can you update views containing a GROUP BY clause in the SELECT statement, or views containing a UNION operation. In all these cases, there is no way to translate the UPDATE into an action on the underlying tables.

Copying views

In Sybase Central, you can copy views between databases. To do so, select the view in the right pane of Sybase Central and drag it to the Views folder of another connected database. A new view is then created, and the original view’s code is copied to it. Note that only the view code is copied to the new view. The other view properties, such as permissions, are not copied.

Using the WITH CHECK OPTION clause
Even when INSERT and UPDATE statements are allowed against a view, it is possible that the inserted or updated rows in the underlying tables may not meet the requirements for the view itself. For example, the view would have no new rows even though the INSERT or UPDATE does modify the underlying tables. Examples using the WITH CHECK OPTION clause 140 The following set of examples illustrates the meaning and usefulness of the WITH CHECK OPTION clause. This optional clause is the final clause in the CREATE VIEW statement.

Chapter 4 Working with Database Objects
v To create a view displaying the employees in the sales department (SQL):

Type the following statements:
CREATE VIEW sales_employee AS SELECT emp_id, emp_fname, emp_lname, dept_id FROM employee WHERE dept_id = 200

The contents of this view are as follows:
SELECT * FROM sales_employee

They appear in Interactive SQL as follows:
Emp_id 129 195 299 467 641 … Emp_fname Philip Marc Rollin James Thomas Emp_lname Chin Dill Overbey Klobucher Powell Dept_id 200 200 200 200 200

Transfer Philip Chin to the marketing department This view update causes the entry to vanish from the view, as it no longer meets the view selection criterion. UPDATE sales_employee SET dept_id = 400 WHERE emp_id = 129

List all employees in the sales department SELECT * FROM sales_employee

Inspect the view.

141

Working with views

Emp_id 195 299 467 641 667 …

emp_fname Marc Rollin James Thomas Mary

emp_lname Dill Overbey Klobucher Powell Garcia

dept_id 200 200 200 200 200

When you create a view using the WITH CHECK OPTION, any UPDATE or INSERT statement on the view is checked to ensure that the new row matches the view condition. If it does not, the operation causes an error and is rejected. The following modified sales_employee view rejects the update statement, generating the following error message:
Invalid value for column ’dept_id’ in table ’employee’

Create a view displaying the employees in the sales department (second attempt) Use WITH CHECK OPTION this time. CREATE VIEW sales_employee AS SELECT emp_id, emp_fname, emp_lname, dept_id FROM employee WHERE dept_id = 200 WITH CHECK OPTION

The check option is inherited

If a view (say V2) is defined on the sales_employee view, any updates or inserts on V2 that cause the WITH CHECK OPTION criterion on sales_employee to fail are rejected, even if V2 is defined without a check option.

Modifying views
You can modify a view using both Sybase Central and Interactive SQL. When doing so, you cannot rename an existing view directly. Instead, you must create a new view with the new name, copy the previous code to it, and then delete the old view. In Sybase Central, a Code Editor lets you edit the code of views, procedures, and functions. In Interactive SQL, you can use the ALTER VIEW statement to modify a view. The ALTER VIEW statement replaces a view definition with a new definition, but it maintains the permissions on the view.

142

Chapter 4 Working with Database Objects

$ For information on altering database object properties, see "Setting
properties for database objects" on page 120.

$ For information on setting permissions, see "Granting permissions on
tables" on page 743 and "Granting permissions on views" on page 745. For information about revoking permissions, see "Revoking user permissions" on page 750.
v To edit a view definition (Sybase Central):

1 2 3 4

Open the Views folder. Right-click the desired view and choose Open from the popup menu. In the Code Editor, edit the view’s code. To execute the code in the database, choose File®Save View.

v To edit a view definition (SQL):

1 2 Example

Connect to a database with DBA authority or as the owner of the view. Execute an ALTER VIEW statement.

Rename the column names of the DepartmentSize view (described in the "Creating views" on page 138 section) so that they have more informative names.
ALTER VIEW DepartmentSize (Dept_ID, NumEmployees) AS SELECT dept_ID, count(*) FROM Employee GROUP BY dept_ID

$ For more information, see "ALTER VIEW statement" on page 399 of
the book ASA Reference.

Deleting views
You can delete a view in both Sybase Central and Interactive SQL.
v To delete a view (Sybase Central):

1 2

Open the Views folder. Right-click the desired view and choose Delete from the popup menu.

143

Working with views
v To delete a view (SQL):

1 2 Examples

Connect to a database with DBA authority or as the owner of the view. Execute a DROP VIEW statement.

Remove a view called DepartmentSize.
DROP VIEW DepartmentSize

$ For more information, see "DROP statement" on page 505 of the book
ASA Reference.

Browsing the information in views
To browse the data held within the views, you can use the Interactive SQL utility. This utility lets you execute queries to identity the data you want to view. For more information about using these queries, see "Queries: Selecting Data from a Table" on page 149. If you are working in Sybase Central, you can right-click a view on which you have permission and choose View Data from the popup menu. This command opens Interactive SQL with the view contents showing in the Results pane. To browse the view, Interactive SQL executes a select * from <owner>, <view> statement.

Views in the system tables
All the information about views in a database is held in the system table SYS.SYSTABLE. The information is presented in a more readable format in the system view SYS.SYSVIEWS. For more information about these, see "SYSTABLE system table" on page 1039 of the book ASA Reference, and "SYSVIEWS system view" on page 1076 of the book ASA Reference. You can use Interactive SQL to browse the information in these tables. Type the following statement in the SQL Statements pane to see all the columns in the SYS.SYSVIEWS view:
SELECT * FROM SYS.SYSVIEWS

To extract a text file containing the definition of a specific view, use a statement such as the following:
SELECT viewtext FROM SYS.SYSVIEWS WHERE viewname = ’DepartmentSize’; OUTPUT TO viewtext.sql FORMAT ASCII

144

Chapter 4 Working with Database Objects

Working with indexes
Performance is an important consideration when designing and creating your database. Indexes can dramatically improve the performance of statements that search for a specific row or a specific subset of the rows. When to use indexes An index provides an ordering on the columns of a table. An index is like a telephone book that initially sorts people by surname, and then sorts identical surnames by first names. This ordering speeds up searches for phone numbers for a particular surname, but it does not provide help in finding the phone number at a particular address. In the same way, a database index is useful only for searches on a specific column or columns. The database server automatically tries to use an index when a suitable index exists and when using one will improve performance. Indexes get more useful as the size of the table increases. The average time to find a phone number at a given address increases with the size of the phone book, while it does not take much longer to find the phone number of, say, K. Kaminski, in a large phone book than in a small phone book. Use indexes for frequentlysearched columns Indexes require extra space and may slightly reduce the performance of statements that modify the data in the table, such as INSERT, UPDATE, and DELETE statements. However, they can improve search performance dramatically and are highly recommended whenever you search data frequently.

$ For more information about performance, see "Using indexes to
improve query performance" on page 816. If a column is already a primary key or foreign key, searches are fast on it because Adaptive Server Anywhere automatically indexes key columns. Thus, manually creating an index on a key column is not necessary and generally not recommended. If a column is only part of a key, an index may help.
When indexes on primary keys may be useful

An index on a key column may assist performance when a large number of foreign keys reference a primary key. Adaptive Server Anywhere automatically uses indexes to improve the performance of any database statement whenever it can. There is no need to refer to indexes once they are created. Also, the index is updated automatically when rows are deleted, updated or inserted.

$ For information on altering database object properties, see "Setting
properties for database objects" on page 120. 145

Working with indexes

Creating indexes
Indexes are created on a specified table. You cannot create an index on a view. To create an index, you can use either Sybase Central or Interactive SQL.
v To create a new index for a given table (Sybase Central):

1 2 3 4 5

Open the Tables folder. Double-click a table. Open the Indexes folder for that table. In the right pane, double-click Add Index. Follow the instructions of the wizard. All indexes appear in the Indexes folder of the associated table.

v To create a new index for a given table (SQL):

1 2 Example

Connect to a database with DBA authority or as the owner of the table on which the index is created. Execute a CREATE INDEX statement.

To speed up a search on employee surnames in the sample database, you could create an index called EmpNames with the following statement:
CREATE INDEX EmpNames ON employee (emp_lname, emp_fname)

$ For more information, see "CREATE INDEX statement" on page 448
of the book ASA Reference, and "Monitoring and Improving Performance" on page 799

Validating indexes
You can validate an index to ensure that every row referenced in the index actually exists in the table. For foreign key indexes, a validation check also ensures that the corresponding row exists in the primary table, and that their hash values match. This check complements the validity checking carried out by the VALIDATE TABLE statement.
v To validate an index (Sybase Central):

1

Connect to a database with DBA authority or as the owner of the table on which the index is created.

146

Chapter 4 Working with Database Objects
2 3 4 5 Open the Tables folder. Double-click a table. Open the Indexes folder for that table. Right-click the index and choose Validate from the popup menu.

v To validate an index (SQL):

1 2

Connect to a database with DBA authority or as the owner of the table on which the index is created. Execute a VALIDATE INDEX statement.

v To validate an index (command line):

1 2 Examples

Open a command prompt. From a command line, run the dbvalid utility.

Validate an index called EmployeeIndex. If you supply a table name instead of an index name, the primary key index is validated.
VALIDATE INDEX EmployeeIndex

Validate an index called EmployeeIndex. The -i switch specifies that each object name given is an index.
dbvalid –i EmployeeIndex

$ For more information, see "VALIDATE INDEX statement" on
page 643 of the book ASA Reference, and "The Validation utility" on page 148 of the book ASA Reference.

Deleting indexes
If an index is no longer required, you can remove it from the database in Sybase Central or in Interactive SQL.
v To delete an index (Sybase Central):

1 2

For the desired table, open the Indexes folder. Right-click the desired index and choose Delete from the popup menu.

v To delete an index (SQL):

1

Connect to a database with DBA authority or as the owner of the table associated with the index. 147

Working with indexes
2 Example Execute a DROP INDEX statement.

The following statement removes the index from the database:
DROP INDEX EmpNames

$ For more information, see "DROP statement" on page 505 of the book
ASA Reference.

Indexes in the system tables
All the information about indexes in a database is held in the system tables SYS.SYSINDEX and SYS.SYSIXCOL. The information is presented in a more readable format in the system view SYS.SYSINDEXES. You can use Sybase Central or Interactive SQL to browse the information in these tables.

148

C H A P T E R

5

Queries: Selecting Data from a Table

About this chapter

The SELECT statement retrieves data from the database. You can use it to retrieve a subset of the rows in one or more tables and to retrieve a subset of the columns in one or more tables. This chapter focuses on the basics of single-table SELECT statements. Advanced uses of SELECT are described later in this manual.

Contents

Topic Query overview The SELECT clause: specifying columns The FROM clause: specifying tables The WHERE clause: specifying rows

Page 150 153 161 162

149

Query overview

Query overview
A query requests data from the database and receives the results. This process is also known as data retrieval. All SQL queries are expressed using the SELECT statement.

Queries are made up of clauses
You construct SELECT statements from clauses. In the following SELECT syntax, each new line is a separate clause. Only the more common clauses are listed here.
SELECT select-list [ FROM table-expression ] [ ON search-condition ] [ WHERE search-condition ] [ GROUP BY column-name ] [ HAVING search-condition ] [ ORDER BY { expression | integer } ]

The clauses in the SELECT statement are as follows: ♦ ♦ The SELECT clause specifies the columns you want to retrieve. It is the only required clause in the SELECT statement. The FROM clause specifies the tables from which columns are pulled. It is required in all queries that retrieve data from tables. In the current chapter, the table-expression is a single table name. SELECT statements without FROM clauses have a different meaning, and we ignore them in this chapter. The ON clause specifies how tables in the FROM clause are to be joined. It is used only for multi-table queries and is not discussed in this chapter. The WHERE clause specifies the rows in the tables you want to see. The GROUP BY clause allows you to collect aggregate data. The HAVING clause specifies rows on which aggregate data is to be collected. By default, rows are returned from relational databases in an order that has no meaning. You can use the ORDER BY clause to sort the rows in the result set.

♦ ♦ ♦ ♦

Most of the clauses are optional, but if they are included then they must appear in the correct order. 150

Chapter 5 Queries: Selecting Data from a Table

$ For a complete listing of the syntax of the SELECT statement syntax,
see "SELECT statement" on page 601 of the book ASA Reference. This chapter discusses only the following set of queries: ♦ Queries with only a single table in the FROM clause. For information on multi-table queries, see "Joins: Retrieving Data from Several Tables" on page 195. Queries with no GROUP BY, HAVING, or ORDER BY clauses. For information on these, see "Summarizing, Grouping, and Sorting Query Results" on page 173.

Entering queries
In this manual, SELECT statements and other SQL statements are displayed with each clause on a separate row, and with the SQL keywords in upper case. This is not a requirement. You can enter SQL keywords in any case, and you can break lines at any point. Keywords and line breaks For example, the following SELECT statement finds the first and last names of contacts living in California from the Contact table.
SELECT first_name, last_name FROM Contact WHERE state = ’CA’

It is equally valid, though not as readable, to enter this statement as follows:
SELECT first_name, last_name from contact wHere state = ’CA’

Case sensitivity of strings and identifiers

Identifiers (that is, table names, column names, and so on) are case insensitive in Adaptive Server Anywhere databases. Strings are case sensitive by default, so that ’CA’, ’ca’, ’cA’, and ’Ca’ are equivalent, but if you create a database as case-sensitive then the case of strings is significant. The sample database is case insensitive. You can qualify the names of database identifiers if there is ambiguity about which object is being referred to. For example, the sample database contains several tables with a column called city, so you may have to qualify references to city with the name of the table. In a larger database you may also have to use the name of the owner of the table to identify the table.
SELECT dba.contact.city FROM contact WHERE state = ’CA’

Qualifying identifiers

151

Query overview
Since the examples in this chapter involve single-table queries, column names in syntax models and examples are usually not qualified with the names of the tables or owners to which they belong. These elements are left out for readability; it is never wrong to include qualifiers. The remaining sections in this chapter analyze the syntax of the SELECT statement in more detail.

152

Chapter 5 Queries: Selecting Data from a Table

The SELECT clause: specifying columns
The select list The select list commonly consists of a series of column names separated by commas, or an asterisk as shorthand to represent all columns. More generally, the select list can include one or more expressions, separated by commas. The general syntax for the select list looks like this:
SELECT expression [, expression ]...

If any table or column name in the list does not conform to the rules for valid identifiers, you must enclose the identifier in double quotes. The select list expressions can include * (all columns), a list of column names, character strings, column headings, and expressions including arithmetic operators. You can also include aggregate functions, which are discussed in "Summarizing, Grouping, and Sorting Query Results" on page 173.

$ For a complete listing of what expressions can consist of, see
"Expressions" on page 230 of the book ASA Reference. The following sections provide examples of the kinds of expressions you can use in a select list.

Selecting all columns from a table
The asterisk (*) has a special meaning in SELECT statements. It stands for all the column names in all the tables specified by the FROM clause. You can use it to save typing time and errors when you want to see all the columns in a table. When you use SELECT *, the columns are returned in the order in which they were defined when the table was created. The syntax for selecting all the columns in a table is:
SELECT * FROM table-expression

SELECT * finds all the columns currently in a table, so that changes in the structure of a table such as adding, removing, or renaming columns automatically modify the results of SELECT *. Listing the columns individually gives you more precise control over the results. Example The following statement retrieves all columns in the department table. No WHERE clause is included; and so this statement retrieves every row in the table: 153

The SELECT clause: specifying columns
SELECT * FROM department

The results look like this:
dept_id 100 200 300 400 500 dept_name R&D Sales Finance Marketing Shipping dept_head_id 501 904 1293 1576 703

You get exactly the same results by listing all the column names in the table in order after the SELECT keyword:
SELECT dept_id, dept_name, dept_head_id FROM department

Like a column name, "*" can be qualified with a table name, as in the following query:
SELECT department.* FROM department

Selecting specific columns from a table
To SELECT only specific columns in a table, use this syntax:
SELECT column_name [, column_name ]... FROM table-name

You must separate each column name from the column name that follows it with a comma, for example:
SELECT emp_lname, emp_fname FROM employee

Rearranging the order of columns

The order in which you list the column names determines the order in which the columns are displayed. The two following examples show how to specify column order in a display. Both of them find and display the department names and identification numbers from all five of the rows in the department table, but in a different order.
SELECT dept_id, dept_name FROM department

154

Chapter 5 Queries: Selecting Data from a Table

dept_id 100 200 300 400 500

dept_name R&D Sales Finance Marketing Shipping

SELECT dept_name, dept_id FROM department dept_name R&D Sales Finance Marketing Shipping dept_id 100 200 300 400 500

Renaming columns using aliases in query results
Query results consist of a set of columns. By default, the heading for each column is the expression supplied in the select list. When query results are displayed, each column’s default heading is the name given to it when it was created. You can specify a different column heading, or alias, in one of the following ways:
SELECT column-name AS alias SELECT column-name alias SELECT alias = column-name

Providing an alias can produce more readable results. For example, you can change dept_name to Department in a listing of departments as follows:
SELECT dept_name AS Department, dept_id AS "Identifying Number" FROM department

155

The SELECT clause: specifying columns

Department R&D Sales Finance Marketing Shipping

Identifying Number 100 200 300 400 500

Using spaces and keywords in alias

The Identifying Number alias for dept_id is enclosed in double quotes because it is an identifier. You also use double quotes if you wish to use keywords in aliases. For example, the following query is invalid without the quotation marks:
SELECT dept_name AS Department, dept_id AS "integer" FROM department

If you wish to ensure compatibility with Adaptive Server Enterprise, you should use quoted aliases of 30 bytes or less.

Character strings in query results
The SELECT statements you have seen so far produce results that consist solely of data from the tables in the FROM clause. Strings of characters can also be displayed in query results by enclosing them in single quotation marks and separate them from other elements in the select list with commas. To enclose a quotation mark in a string, you precede it with another quotation mark. For example:
SELECT ’The department’’s name is’ AS " ", Department = dept_name FROM department Department The department’s name is The department’s name is The department’s name is The department’s name is The department’s name is R&D Sales Finance Marketing Shipping

156

Chapter 5 Queries: Selecting Data from a Table

Computing values in the select list
The expressions in the select list can be more complicated than just column names or strings. For example, you can perform computations with data from numeric columns in a select list. Arithmetic operations To illustrate the numeric operations you can carry out in the select list, we start with a listing of the names, quantity in stock, and unit price of products in the sample database. The number of zeroes in the unit_price column is truncated for readability.
SELECT name, quantity, unit_price FROM product name Tee Shirt Tee Shirt Tee Shirt Baseball Cap Baseball Cap Visor Visor Sweatshirt Sweatshirt Shorts quantity 28 54 75 112 12 36 28 39 32 80 unit_price 9.00 14.00 14.00 9.00 10.00 7.00 7.00 24.00 24.00 15.00

Suppose the practice is to replenish the stock of a product when there are ten items left in stock. The following query lists the number of each product that must be sold before re-ordering:
SELECT name, quantity - 10 AS "Sell before reorder" FROM product name Tee Shirt Tee Shirt Tee Shirt Baseball Cap Baseball Cap Sell before reorder 18 44 65 102 2

157

The SELECT clause: specifying columns
name Visor Visor Sweatshirt Sweatshirt Shorts Sell before reorder 26 18 29 22 70

You can also combine the values in columns. The following query lists the total value of each product in stock:
SELECT name, quantity * unit_price AS "Inventory value" FROM product name Tee Shirt Tee Shirt Tee Shirt Baseball Cap Baseball Cap Visor Visor Sweatshirt Sweatshirt Shorts Inventory value 252.00 756.00 1050.00 1008.00 120.00 252.00 196.00 936.00 768.00 1200.00

Arithmetic operator precedence

When there is more than one arithmetic operator in an expression, multiplication, division, and modulo are calculated first, followed by subtraction and addition. When all arithmetic operators in an expression have the same level of precedence, the order of execution is left to right. Expressions within parentheses take precedence over all other operations. For example, the following SELECT statement calculates the total value of each product in inventory, and then subtracts five dollars from that value.
SELECT name, quantity * unit_price - 5 FROM product

To avoid misunderstandings, it is recommended that you use parentheses. The following query has the same meaning and gives the same results as the previous one, but some may find it easier to understand: 158

Chapter 5 Queries: Selecting Data from a Table
SELECT name, ( quantity * unit_price ) - 5 FROM product

$ For more information on operator precedence, see "Operator
precedence" on page 228 of the book ASA Reference. String operations You can concatenate strings using a string concatenation operator. You can use either || (SQL/92 compliant) or + (supported by Adaptive Server Enterprise) as the concatenation operator. The following example illustrates the use of the string concatenation operator in the select list:
SELECT emp_id, emp_fname || ’ ’ || emp_lname AS Name FROM employee emp_id 102 105 129 148 ... Name Fran Whitney Matthew Cobb Philip Chin Julie Jordan ...

Date and time operations

Although you can use operators on date and time columns, this typically involves the use of functions. For information on SQL functions, see "SQL Functions" on page 303 of the book ASA Reference.

Eliminating duplicate query results
The optional DISTINCT keyword eliminates duplicate rows from the results of a SELECT statement. If you do not specify DISTINCT, you get all rows, including duplicates. Optionally, you can specify ALL before the select list to get all rows. For compatibility with other implementations of SQL, Adaptive Server syntax allows the use of ALL to explicitly ask for all rows. ALL is the default. For example, if you search for all the cities in the contact table without DISTINCT, you get 60 rows:
SELECT city FROM contact

You can eliminate the duplicate entries using DISTINCT. The following query returns only 16 rows.:
SELECT DISTINCT city

159

The SELECT clause: specifying columns
FROM contact

NULL values are not distinct

The DISTINCT keyword treats NULL values as duplicates of each other. In other words, when DISTINCT is included in a SELECT statement, only one NULL is returned in the results, no matter how many NULL values are encountered.

160

Chapter 5 Queries: Selecting Data from a Table

The FROM clause: specifying tables
The FROM clause is required in every SELECT statement involving data from tables or views.

$ The FROM clause can include JOIN conditions linking two or more tables, and can include joins to other queries (derived tables). For information on these features, see "Joins: Retrieving Data from Several Tables" on page 195.
Qualifying table names In the FROM clause, the full naming syntax for tables and views is always permitted, such as:
SELECT select-list FROM owner.table_name

Qualifying table and view names is necessary only when there might be some confusion about the name. Using correlation names You can give table names correlation names to save typing. You assign the correlation name in the FROM clause by entering it after the table name, like this:
SELECT d.dept_id, d.dept_name FROM Department d

All other references to the Department table, for example in a WHERE clause, must use the correlation name. Correlation names must conform to the rules for valid identifiers.

161

The WHERE clause: specifying rows

The WHERE clause: specifying rows
The WHERE clause in a SELECT statement specifies the search conditions for exactly which rows are retrieved. The general format is:
SELECT select_list FROM table_list WHERE search-condition

Search conditions, (also called qualifications or predicates), in the WHERE clause include the following: ♦
Comparison operators

(=, <, >, and so on) For example, you can list all employees earning more than $50,000:
SELECT emp_lname FROM employee WHERE salary > 50000

Ranges (BETWEEN and NOT BETWEEN) For example, you can list all employees earning between $40,000 and $60,000: SELECT emp_lname FROM employee WHERE salary BETWEEN 40000 AND 60000

Lists

(IN, NOT IN) For example, you can list all customers in Ontario, Quebec, or Manitoba:
SELECT company_name , state FROM customer WHERE state IN( ’ON’, ’PQ’, ’MB’)

Character matches

(LIKE and NOT LIKE) For example, you can list all customers whose phone numbers start with 415. (The phone number is stored as a string in the database):
SELECT company_name , phone FROM customer WHERE phone LIKE ’415%’

Unknown values

(IS NULL and IS NOT NULL) For example, you can list all departments with managers:
SELECT dept_name FROM Department WHERE dept_head_id IS NOT NULL

Combinations (AND, OR) For example, you can list all employees earning over $50,000 whose first name begins with the letter A. SELECT emp_fname, emp_lname FROM employee WHERE salary > 50000

162

Chapter 5 Queries: Selecting Data from a Table
AND emp_fname like ’A%’

In addition, the WHERE keyword can introduce the following: ♦
Transact-SQL join conditions

Joins are discussed in "Joins: Retrieving Data from Several Tables" on page 195.

$ The following sections describe how to use WHERE clauses. For a complete listing of search conditions, see "Search conditions" on page 239 of the book ASA Reference.

Using comparison operators in the WHERE clause
You can use comparison operators in the WHERE clause. The operators follow the syntax:
WHERE expression comparison-operator expression

$ For a listing of comparison operators, see "Comparison operators" on
page 225 of the book ASA Reference. For a description of what an expression can be, see "Expressions" on page 230 of the book ASA Reference. Notes on comparisons ♦
Sort orders In comparing character data, < means earlier in the sort order and > means later in the sort order. The sort order is determined by the collation chosen when the database is created. You can find out the collation by running the dbinfo command-line utility against the database: dbinfo -c "uid=dba;pwd=sql"

You can also find the collation from Sybase Central. It is on the Extended Information tab of the database property sheet. ♦
Trailing blanks When you create a database, you indicate whether trailing blanks are to be ignored or not for the purposes of comparison.

By default, databases are created with trailing blanks not ignored. For example, ’Dirk’ is not the same as ’Dirk ’. You can create databases with blank padding, so that trailing blanks are ignored. Trailing blanks are ignored by default in Adaptive Server Enterprise databases. ♦ ♦
Comparing dates

In comparing dates, < means earlier and > means

later.
Case sensivitivity When you create a database, you indicate whether string comparisons are case sensitive or not.

By default, databases are created case insensitive. For example, ’Dirk’ is the same as ’DIRK’. You can create databases to be case sensitive, which is the default behavior for Adaptive Server Enterprise databases. 163

The WHERE clause: specifying rows
Here are some SELECT statements using comparison operators:
SELECT * FROM product WHERE quantity < 20 SELECT E.emp_lname, E.emp_fname FROM employee E WHERE emp_lname > ’McBadden’ SELECT id, phone FROM contact WHERE state != ’CA’

The NOT operator

The NOT operator negates an expression. Either of the following two queries will find all Tee shirts and baseball caps that cost $10 or less. However, note the difference in position between the negative logical operator (NOT) and the negative comparison operator (!>).
SELECT id, name, quantity FROM product WHERE (name = ’Tee Shirt’ OR name = ’BaseBall Cap’) AND NOT unit_price > 10 SELECT id, name, quantity FROM product WHERE (name = ’Tee Shirt’ OR name = ’BaseBall Cap’) AND unit_price !> 10

Using ranges (between and not between) in the WHERE clause
The BETWEEN keyword specifies an inclusive range, in which the lower value and the upper value are searched for as well as the values they bracket.
v To list all the products with prices between $10 and $15, inclusive:

Enter the following query:
SELECT name, unit_price FROM product WHERE unit_price BETWEEN 10 AND 15

name Tee Shirt Tee Shirt Baseball Cap Shorts

unit_price 14.00 14.00 10.00 15.00

164

Chapter 5 Queries: Selecting Data from a Table
You can use NOT BETWEEN to find all the rows that are not inside the range.
v To list all the products cheaper than $10 or more expensive than $15:

Enter the following query:
SELECT name, unit_price FROM product WHERE unit_price NOT BETWEEN 10 AND 15

name Tee Shirt Tee Shirt Visor Visor Sweatshirt Sweatshirt

unit_price 9.00 9.00 7.00 7.00 24.00 24.00

Using lists in the WHERE clause
The IN keyword allows you to select values that match any one of a list of values. The expression can be a constant or a column name, and the list can be a set of constants or, more commonly, a subquery. For example, without in, if you want a list of the names and states of all the contacts who live in Ontario, Manitoba, or Quebec, you can type this query:
SELECT company_name , state FROM customer WHERE state = ’ON’ OR state = ’MB’ OR state = ’PQ’

However, you get the same results if you use IN. The items following the IN keyword must be separated by commas and enclosed in parentheses. Put single quotes around character, date, or time values. For example:
SELECT company_name , state FROM customer WHERE state IN( ’ON’, ’MB’, ’PQ’)

Perhaps the most important use for the IN keyword is in nested queries, also called subqueries.

165

The WHERE clause: specifying rows

Matching character strings in the WHERE clause
The LIKE keyword indicates that the following character string is a matching pattern. LIKE is used with character, binary, or date and time data. The syntax for like is:
{ WHERE | HAVING } expression [ NOT ] LIKE match-expression

The expression to be matched is compared to a match-expression that can include these special symbols:
Symbols % _ [specifier] Meaning Matches any string of 0 or more characters Matches any one character The specifier in the brackets may take the following forms:

♦ Range A range is of the form rangespec1-rangespec2, where
rangespec1 indicates the start of a range of characters, the hyphen indicates a range, and rangespec2 indicates the end of a range of characters

♦ Set A set can be comprised of any discrete set of values, in any order.
For example, [a2bR]. Note that the range [a-f], and the sets [abcdef] and [fcbdae] return the same set of values. [^specifier] The caret symbol (^) preceding a specifier indicates non-inclusion. [^a-f] means not in the range a-f; [^a2bR] means not a, 2, b, or R.

You can match the column data to constants, variables, or other columns that contain the wildcard characters shown in the table. When using constants, you should enclose the match strings and character strings in single quotes. Examples All the following examples use LIKE with the last_name column in the Contact table. Queries are of the form:
SELECT last_name FROM contact WHERE last_name LIKE match-expression

The first example would be entered as
SELECT last_name FROM contact WHERE last_name LIKE ’Mc%’

166

Chapter 5 Queries: Selecting Data from a Table

Match expression ’Mc%’ ’%er’ ’%en%’ ’_ish’ ’Br[iy][ae]r’ ’[M-Z]owell’ ’M[^c]%’

Description Search for every name that begins with the letters Mc Search for every name that ends with er Search for every name containing the letters en. Search for every four-letter name ending in ish. Search for Brier, Bryer, Briar, or Bryar. Search for all names ending with owell that begin with a single letter in the range M to Z. Search for all names beginning with M’ that do not have c as the second letter

Returns McEvoy Brier, Miller, Weaver, Rayner Pettengill, Lencki, Cohen Fish Brier Powell Moore, Mulley, Miller, Masalsky

Wildcards require LIKE

Wildcard characters used without LIKE are interpreted as literals rather than as a pattern: they represent exactly their own values. The following query attempts to find any phone numbers that consist of the four characters 415% only. It does not find phone numbers that start with 415.
SELECT phone FROM Contact WHERE phone = ’415%’

Using LIKE with date and time values

You can use LIKE on date and time fields as well as on character data. When you use LIKE with date and time values, the dates are converted to the standard DATETIME format, and then to VARCHAR. One feature of using LIKE when searching for DATETIME values is that, since date and time entries may contain a variety of date parts, an equality test has to be written carefully in order to succeed. For example, if you insert the value 9:20 and the current date into a column named arrival_time, the clause:
WHERE arrival_time = ’9:20’

fails to find the value, because the entry holds the date as well as the time. However, the clause below would find the 9:20 value:
WHERE arrival_time LIKE ’%9:20%’

Using NOT LIKE

With NOT LIKE, you can use the same wildcard characters that you can use with LIKE. To find all the phone numbers in the Contact table that do not have 415 as the area code, you can use either of these queries: 167

The WHERE clause: specifying rows
SELECT phone FROM Contact WHERE phone NOT LIKE ’415%’ SELECT phone FROM Contact WHERE NOT phone LIKE ’415%’

Character strings and quotation marks
When you enter or search for character and date data, you must enclose it in single quotation marks, as in the following example.
SELECT first_name, last_name FROM contact WHERE first_name = ’John’

If the quoted_identifier database option is set to OFF (it is ON by default), you can also use double quotes around character or date data.
v To set the quoted_identifier option off for the current user ID:

Type the following command:
SET OPTION quoted_identifier = ’OFF’

The quoted_identifier option is provided for compatibility with Adaptive Server Enterprise. By default, the Adaptive Server Enterprise option is quoted_identifier OFF and the Adaptive Server Anywhere option is quoted_identifier ON. Quotation marks in strings There are two ways to specify literal quotations within a character entry. The first method is to use two consecutive quotation marks. For example, if you have begun a character entry with a single quotation mark and want to include a single quotation mark as part of the entry, use two single quotation marks:
’I don’’t understand.’

With double quotation marks (quoted_identifier OFF):
"He said, ""It is not really confusing."""

The second method, applicable only with quoted_identifier OFF, is to enclose a quotation in the other kind of quotation mark. In other words, surround an entry containing double quotation marks with single quotation marks, or vice versa. Here are some examples:
’George said, "There must be a better way."’ "Isn’t there a better way?" ’George asked, "Isn’’t there a better way?"’

168

Chapter 5 Queries: Selecting Data from a Table

Unknown Values: NULL
A NULL in a column means that the user or application has made no entry in that column. A data value for the column is unknown or not available NULL does not mean the same as zero (numerical values) or blank (character values). Rather, NULL values allow you to distinguish between a deliberate entry of zero for numeric columns or blank for character columns and a non-entry, which is NULL for both numeric and character columns. Entering NULL NULL can be entered in a column where NULL values are permitted, as specified in the create table statement, in two ways: ♦ ♦
Default

If no data is entered, and the column has no other default setting, NULL is entered.

Explicit entry You can explicitly enter the value NULL by typing the word NULL (without quotation marks).

If the word NULL is typed in a character column with quotation marks, it is treated as data, not as a null value. For example, the dept_head_id column of the department table allows nulls. You can enter two rows for departments with no manager as follows:
INSERT INTO department (dept_id, dept_name) VALUES (201, ’Eastern Sales’) INSERT INTO department VALUES (202, ’Western Sales’, null)

When NULLs are retrieved

When NULLS are retrieved, displays of query results in Interactive SQL show (NULL) in the appropriate position:
SELECT * FROM department dept_id 100 200 300 400 500 201 202 dept_name R&D Sales Finance Marketing Shipping Eastern Sales Western Sales dept_head_id 501 904 1293 1576 703 (NULL) (NULL)

169

The WHERE clause: specifying rows

Testing a column for NULL
You can use IS NULL in search conditions to compare column values to NULL and to select them or perform a particular action based on the results of the comparison. Only columns that return a value of TRUE are selected or result in the specified action; those that return FALSE or UNKNOWN do not. The following example selects only rows for which unit_price is less than $15 or is NULL:
SELECT quantity , unit_price FROM product WHERE unit_price < 15 OR unit_price IS NULL

The result of comparing any value to NULL is UNKNOWN, since it is not possible to determine whether NULL is equal (or not equal) to a given value or to another NULL. There are some conditions that never return true, so that queries using these conditions do not return result sets. For example, the following comparison can never be determined to be true, since NULL means having an unknown value:
WHERE column1 > NULL

This logic also applies when you use two column names in a WHERE clause, that is, when you join two tables. A clause containing the condition
WHERE column1 = column2

does not return rows where the columns contain NULL. You can also find NULL or non-NULL with this pattern:
WHERE column_name IS [NOT] NULL

For example:
WHERE advance < $5000 OR advance IS NULL

$ For more information, see "NULL value" on page 260 of the book ASA
Reference.

Properties of NULL
The following list expands on the properties of NULL. ♦
The difference between FALSE and UNKNOWN

Although neither FALSE nor UNKNOWN returns values, there is an important logical difference between FALSE and UNKNOWN, because the opposite of false ("not false") is true. For example,

170

Chapter 5 Queries: Selecting Data from a Table
1 = 2

evaluates to false and its opposite,
1 != 2

evaluates to true. But "not unknown" is still unknown. If null values are included in a comparison, you cannot negate the expression to get the opposite set of rows or the opposite truth value. ♦
Substituting a value for NULLs

Use the ISNULL built-in function to substitute a particular value for nulls. The substitution is made only for display purposes; actual column values are not affected. The syntax is:
ISNULL( expression, value )

For example, use the following statement to select all the rows from test, and display all the null values in column t1 with the value unknown.
SELECT ISNULL(t1, ’unknown’) FROM test

Expressions that evaluate to NULL An expression with an arithmetic or bitwise operator evaluates to NULL if any of the operands are null. For example: 1 + column1

evaluates to NULL if column1 is NULL. ♦
Concatenating strings and NULL

If you concatenate a string and NULL, the expression evaluates to the string. For example:
SELECT ’abc’ || NULL || ’def’

returns the string abcdef.

Connecting conditions with logical operators
The logical operators AND, OR, and NOT are used to connect search conditions in WHERE clauses. Using AND The AND operator joins two or more conditions and returns results only when all of the conditions are true. For example, the following query finds only the rows in which the contact’s last name is Purcell and the contact’s first name is Beth. It does not find the row for Beth Glassmann.
SELECT * FROM contact WHERE first_name = ’Beth’ AND last_name = ’Purcell’

171

The WHERE clause: specifying rows

Using OR

The OR operator also connects two or more conditions, but it returns results when any of the conditions is true. The following query searches for rows containing variants of Elizabeth in the first_name column.
SELECT * FROM contact WHERE first_name = ’Beth’ OR first_name = ’Liz’

Using NOT

The NOT operator negates the expression that follows it. The following query lists all the contacts who do not live in California:
SELECT * FROM contact WHERE NOT state = ’CA’

When more than one logical operator is used in a statement, AND operators are normally evaluated before OR operators. You can change the order of execution with parentheses. For example:
SELECT * FROM contact WHERE ( city = ’Lexington’ OR city = ’Burlington’ ) AND state = ’MA’

172

C H A P T E R

6

Summarizing, Grouping, and Sorting Query Results

About this chapter

Aggregate functions display summaries of the values in specified columns. You can also use the GROUP BY clause, HAVING clause, and ORDER BY clause to group and sort the results of queries using aggregate functions, and the UNION operator to combine the results of queries. This chapter describes how to group and sort query results.

Contents

Topic Summarizing query results using aggregate functions The GROUP BY clause: organizing query results into groups Understanding GROUP BY The HAVING clause: selecting groups of data The ORDER BY clause: sorting query results The UNION operation: combining queries Standards and compatibility

Page 174 178 180 184 187 190 192

173

Summarizing query results using aggregate functions

Summarizing query results using aggregate functions
You can apply aggregate functions to all the rows in a table, to a subset of the table specified by a WHERE clause, or to one or more groups of rows in the table. From each set of rows to which an aggregate function is applied, Adaptive Server Anywhere generates a single value. Example
v To calculate the total payroll, from the annual salaries in the employee table:

Enter the following query:
SELECT SUM(salary) FROM employee

To use the aggregate functions, you must give the function name followed by an expression on whose values it will operate. The expression, which is the salary column in this example, is the function’s argument and must be specified inside parentheses. The following aggregate functions are available: ♦ ♦ ♦ ♦ ♦ ♦ ♦
avg (expression )

The mean of the supplied expression over the

returned rows.
count ( expression ) The number of rows in the supplied group where the expression is not NULL. count(*)

The number of rows in each group.

list (string-expr)

A string containing a comma-separated list composed of all the values for string-expr in each group of rows. The maximum value of the expression, over the The minimum value of the expression, over the The sum of the expression, over the returned rows. returned rows.

max (expression ) min (expression )

returned rows.
sum(expression )

You can use the optional keyword DISTINCT with AVG, SUM, LIST, and COUNT to eliminate duplicate values before the aggregate function is applied. The expression to which the syntax statement refers is usually a column name. It can also be a more general expression.

174

Chapter 6 Summarizing, Grouping, and Sorting Query Results
For example, with this statement you can find what the average price of all products would be if one dollar were added to each price:
SELECT AVG (unit_price + 1) FROM product

Where you can use aggregate functions
The aggregate functions can be used in a select list, as in the previous examples, or in the HAVING clause of a select statement that includes a GROUP BY clause.

$ For information about the HAVING clause, see "The HAVING clause:
selecting groups of data" on page 184. You cannot use aggregate functions in a WHERE clause or in a JOIN condition. However, a SELECT statement with aggregate functions in its select list often includes a WHERE clause that restricts the rows to which the aggregate is applied. If a SELECT statement includes a WHERE clause, but not a GROUP BY clause, an aggregate function produces a single value for the subset of rows that the WHERE clause specifies. Whenever an aggregate function is used in a SELECT statement that does not include a GROUP BY clause, it produces a single value, called a scalar aggregate. This is true whether it is operating on all the rows in a table or on a subset of rows defined by a where clause. You can use more than one aggregate function in the same select list, and produce more than one scalar aggregate in a single SELECT statement.

Aggregate functions and data types
There are some aggregate functions that have meaning only for certain kinds of data. For example, you can use SUM and AVG with numeric columns only. However, you can use MIN to find the lowest value—the one closest to the beginning of the alphabet—in a character type column:
SELECT MIN(last_lname) FROM contact

175

Summarizing query results using aggregate functions

Using count (*)
The COUNT(*) function does not require an expression as an argument because, by definition, it does not use information about any particular column. The COUNT(*) function finds the total number of rows in a table. This statement finds the total number of employees:
SELECT COUNT(*) FROM employee

COUNT(*) returns the number of rows in the specified table without eliminating duplicates. It counts each row separately, including rows that contain NULL. Like other aggregate functions, you can combine count(*) with other aggregates in the select list, with where clauses, and so on:
SELECT count(*), AVG(unit_price) FROM product WHERE unit_price > 10 count(*) 5 avg(unit_price) 18.200

Using aggregate functions with DISTINCT
The DISTINCT keyword is optional with SUM, AVG, and COUNT. When you use DISTINCT, duplicate values are eliminated before calculating the sum, average, or count. For example, to find the number of different cities in which there are contacts, type:
SELECT count(DISTINCT city) FROM contact count(distinct city) 16

Aggregate functions and NULL
Any NULLS in the column on which the aggregate function is operating are ignored for the purposes of the function except COUNT(*), which includes them. If all the values in a column are NULL, COUNT(column_name) returns 0. 176

Chapter 6 Summarizing, Grouping, and Sorting Query Results
If no rows meet the conditions specified in the WHERE clause, COUNT returns a value of 0. The other functions all return NULL. Here are examples:
SELECT COUNT (DISTINCT name) FROM product WHERE unit_price > 50 count(DISTINCT name) 0 SELECT AVG(unit_price) FROM product WHERE unit_price > 50 AVG ( unit_price) ( NULL )

177

The GROUP BY clause: organizing query results into groups

The GROUP BY clause: organizing query results into groups
The GROUP BY clause divides the output of a table into groups. You can GROUP BY one or more column names, or by the results of computed columns using numeric data types in an expression.

Using GROUP BY with aggregate functions
A GROUP BY clause almost always appears in statements that include aggregate functions, in which case the aggregate produces a value for each group. These values are called vector aggregates. (Remember that a scalar aggregate is a single value produced by an aggregate function without a GROUP BY clause.) Example
v To list the average price of each kind of product:

Enter the following command:
SELECT name, AVG(unit_price) AS Price FROM product GROUP BY name

name Baseball Cap Shorts Sweatshirt Tee Shirt Visor

Price 9.500 15.000 24.000 12.333 7.000

The summary values (vector aggregates) produced by SELECT statements with aggregates and a GROUP BY appear as columns in each row of the results. By contrast, the summary values (scalar aggregates) produced by queries with aggregates and no GROUP BY also appear as columns, but with only one row. For example:
SELECT AVG(unit_price) FROM product AVG(unit_price) 13.300000

178

Chapter 6 Summarizing, Grouping, and Sorting Query Results

179

Understanding GROUP BY

Understanding GROUP BY
Understanding which queries are valid and which are not can be difficult when the query involves a GROUP BY clause. This section describes a way to think about queries with GROUP BY so that you may understand the results and the validity of queries better.

How queries with GROUP BY are executed
Consider a single-table query of the following form:
SELECT select-list FROM table WHERE where-search-condition GROUP BY group-by-expression HAVING having-search-condition

This query can be thought of as being executed in the following manner: 1
Apply the WHERE clause This generates an intermediate result that contains only some of the rows of the table.

Table

Intermediate result
WHERE clause

2

Partition the result into groups

This action generates an intermediate result with one row for each group as dictated by the GROUP BY clause. Each generated row contains the group-by-expression for each group, and the computed aggregate functions in the select-list and having-search-condition.

180

Chapter 6 Summarizing, Grouping, and Sorting Query Results
Second intermediate result
GROUP BY clause

Intermediate result

3

Apply the HAVING clause

Any rows from this second intermediate result that do not meet the criteria of the HAVING clause are removed at this point. This action takes from step 3 only those columns that need to be displayed in the result set of the query – that is, it takes only those columns corresponding to the expressions from the select-list. Second intermediate result
Projection

4

Project out the results to display

Final result

This process makes requirements on queries with a GROUP BY clause: ♦ The WHERE clause is evaluated first. Therefore, any aggregate functions are evaluated only over those rows that satisfy the WHERE clause. The final result set is built from the second intermediate result, which holds the partitioned rows. The second intermediate result holds rows corresponding to the group-by-expression. Therefore, if an expression that is not an aggregate function appears in the select-list, then it must also appear in the group-by-expression. No function evaluation can be carried out during the projection step. An expression can be included in the group-by-expression but not in the select-list. It is projected out in the result.

181

Understanding GROUP BY

GROUP BY with multiple columns
You can list more than one expression in the GROUP BY clause in order to nest groups—that is, you can group a table by any combination of expressions.
v To list the average price of products, grouped first by name and then by size:

Enter the following command:
SELECT name, size, AVG(unit_price) FROM product GROUP BY name, size name Tee Shirt Tee Shirt Tee Shirt Baseball Cap Visor Sweatshirt Shorts size Small Medium One size fits all One size fits all One size fits all Large Medium AVG(unit_price) 9.000 14.000 14.000 9.500 7.000 24.000 15.000

Columns in GROUP BY that are not in the select list

A Sybase extension to the SQL/92 standard that is supported by both Adaptive Server Enterprise and Adaptive Server Anywhere is to allow expressions to the GROUP BY clause that are not in the select list. For example, the following query lists the number of contacts in each city:
SELECT state, count(id) FROM contact GROUP BY state, city

WHERE clause and GROUP BY
You can use a WHERE clause in a statement with GROUP BY. The WHERE clause is evaluated before the GROUP BY clause. Rows that do not satisfy the conditions in the WHERE clause are eliminated before any grouping is done. Here is an example:
SELECT name, AVG(unit_price) FROM product WHERE id > 400 GROUP BY name

182

Chapter 6 Summarizing, Grouping, and Sorting Query Results
Only the rows with id values of more than 400 are included in the groups that are used to produce the query results.

An example
The following query illustrates the use of WHERE, GROUP BY, and HAVING clauses in one query:
SELECT name, SUM(quantity) FROM product WHERE name LIKE ’%shirt%’ GROUP BY name HAVING SUM(quantity) > 100 name Tee Shirt SUM(quantity) 157

In this example: 1 2 3 4 The WHERE clause includes only rows that have a name including the word shirt (Tee Shirt, Sweatshirt). The GROUP BY clause collects the rows with a common name. The SUM aggregate calculates the total quantity of products available for each group. The HAVING clause excludes from the final results the groups whose inventory totals do not exceed 100.

183

The HAVING clause: selecting groups of data

The HAVING clause: selecting groups of data
The HAVING clause restricts the rows returned by a query. It sets conditions for the GROUP BY clause similar to the way in which WHERE sets conditions for the SELECT clause. The HAVING clause search conditions are identical to WHERE search conditions except that WHERE search conditions cannot include aggregates, while HAVING search conditions often do. The example below is legal:
HAVING AVG(unit_price) > 20

But this example is not:
WHERE AVG(unit_price) > 20

Using HAVING with aggregate functions

This statement is an example of simple use of the HAVING clause with an aggregate function.
v To list those products available in more than one size or color:

You need a query to group the rows in the product table by name, but eliminate the groups that include only one distinct product:
SELECT name FROM product GROUP BY name HAVING COUNT(*) > 1 name Baseball Cap Sweatshirt Tee Shirt Visor

Using HAVING without aggregate functions

The HAVING clause can also be used without aggregates.
v To list all product names that start with letter B:

The following query groups the products, and then restricts the result set to only those groups for which the name starts with B.
SELECT name FROM product GROUP BY name HAVING name LIKE ’B%’

184

Chapter 6 Summarizing, Grouping, and Sorting Query Results

name Baseball Cap

More than one condition in HAVING

More than one condition can be included in the HAVING clause. They are combined with the AND, OR, or NOT operators, as the following example shows.
v To list those products available in more than one size or color, for which one version costs more than $10:

You need a query to group the rows in the product table by name, but eliminate the groups that include only one distinct product, and eliminate those groups for which the maximum unit price is under $10:
SELECT name FROM product GROUP BY name HAVING COUNT(*) > 1 AND MAX(unit_price) > 10 name Sweatshirt Tee Shirt

SQL extension

Some of the previous HAVING examples adhere to the SQL/92 standard, which specifies that expressions in a HAVING clause must have a single value, and must be in the select list or GROUP BY clause. However, Adaptive Server Anywhere and Adaptive Server Enterprise support extensions to HAVING that allow aggregate functions not in the select list and not in the GROUP BY clause as the previous example. A column reference in an aggregate function is called an outer reference. When an aggregate function contains an outer reference, then the aggregate function must appear in a subquery of a HAVING clause. The following example illustrates this case.
v To list those products shipped during the year 1993, for which the maximum shipped quantity is greater than the available quantity of that product:

Outer references in aggregate functions

Enter the following query:

185

The HAVING clause: selecting groups of data
SELECT p.id, p.name FROM product p, sales_order_items s WHERE p.id = s.product_id AND ship_date >= ’1993-01-01’ AND ’ship_date <= ’1993-12-31’ GROUP BY p.id HAVING EXISTS SELECT * FROM product.p WHERE MAX (s.quantity) > p.quantity AND p.id = s.product_id id 301 301 401 500 501 600 601 name Tee Shirt Tee Shirt Baseball Cap Visor Visor Sweatshirt Sweatshirt

186

Chapter 6 Summarizing, Grouping, and Sorting Query Results

The ORDER BY clause: sorting query results
The ORDER BY clause allows sorting of query results by one or more columns. Each sort can be ascending (ASC) or descending (DESC). If neither is specified, ASC is assumed. A simple example The following query returns results ordered by name:
SELECT id, name FROM product ORDER BY name id 400 401 700 600 601 300 301 302 500 501 Name Baseball Cap Baseball Cap Shorts Sweatshirt Sweatshirt Tee Shirt Tee Shirt Tee Shirt Visor Visor

Sorting by more than one column

If you name more than one column in the ORDER BY clause, the sorts are nested. The following statement sorts the shirts in the product table first by name in ascending order, then by quantity (descending) within each name:
SELECT id, name, quantity FROM product WHERE name like ’%shirt%’ ORDER BY name, quantity DESC

187

The ORDER BY clause: sorting query results

id 600 601 302 301 300

name Sweatshirt Sweatshirt Tee Shirt Tee Shirt Tee Shirt

Quantity Baseball Cap Baseball Cap Shorts Sweatshirt Sweatshirt

Using the column position

You can use the position number of a column in a select list instead of the column name. Column names and select list numbers can be mixed. Both of the following statements produce the same results as the preceding one.
SELECT id, name, quantity FROM product WHERE name like ’%shirt%’ ORDER BY 2, 3 DESC SELECT id, name, quantity FROM product WHERE name like ’%shirt%’ ORDER BY 2, quantity DESC

Most versions of SQL require that ORDER BY items appear in the select list, but Adaptive Server Anywhere has no such restriction. The following query orders the results by quantity, although that column does not appear in the select list.
SELECT id, name FROM product WHERE name like ’%shirt%’ ORDER BY 2, quantity DESC

ORDER BY and NULL ORDER BY and case sensitivity

With ORDER BY, NULL comes before all other values, whether the sort order is ascending or descending. The effects of an ORDER BY clause on mixed-case data depend on the database collation and case sensitivity specified when the database is created.

Retrieving the first few rows of a query
You can limit the results of a query to the first few rows returned using the FIRST or TOP keywords. While you can use these with any query, they are most useful with queries that use the ORDER BY clause. Examples ♦ The following query returns information about the first employee sorted by last name:

188

Chapter 6 Summarizing, Grouping, and Sorting Query Results
SELECT FIRST * FROM employee ORDER BY emp_lname

The following query returns the first five employees sorted by last name comes earliest in the alphabet:
SELECT TOP 5 * FROM employee ORDER BY emp_lname

ORDER BY and GROUP BY
You can use an ORDER BY clause to order the results of a GROUP BY in a particular way. Example
v To find the average price of each type of book and order the results by average price:

Enter the following statement:
SELECT name, AVG(unit_price) FROM product GROUP BY name ORDER BY AVG(unit_price) Name Visor Baseball Cap Tee Shirt Shorts Sweatshirt AVG(unit_price) 7.000 9.500 12.333 15.000 24.000

189

The UNION operation: combining queries

The UNION operation: combining queries
The UNION operator combines the results of two or more queries into a single result set. By default, the UNION operator removes duplicate rows from the result set. If you use the ALL option, duplicates are not removed. The columns in the result set have the same names as the columns in the first table referenced. Any number of union operators may be used. For example:
x UNION y UNION z

By default, a statement containing multiple UNION operators is evaluated from left to right. Parentheses may be used to specify the order of evaluation. For example, the following two expressions are not equivalent, due to the way that duplicate rows are removed from result sets:
x UNION ALL (y UNION z) (x UNION ALL y) UNION z

In the first expression, duplicates are eliminated in the UNION between y and z. In the UNION between that set and x, duplicates are not eliminated. In the second expression, duplicates are included in the union between x and y, but are then eliminated in the subsequent union with z. Guidelines for UNION queries The following are guidelines to observe when you use union statements: ♦
Same number of items in the select lists

All select lists in the union statement must have the same number of expressions (such as column names, arithmetic expressions, and aggregate functions). The following statement is invalid because the first select list is longer than the second:
-- This is an example of an invalid statement SELECT stor_id, city, state FROM stores UNION SELECT stor_id, city FROM stores_east

Data types must match Corresponding expressions in the SELECT lists must be of the same data type, or an implicit data conversion must be possible between the two data types, or an explicit conversion should be supplied.

For example, a UNION is not possible between a column of the CHAR data type and one of the INT data type, unless an explicit conversion is supplied. However, a union is possible between a column of the MONEY data type and one of the INT data type.

190

Chapter 6 Summarizing, Grouping, and Sorting Query Results

Column ordering

You must place corresponding expressions in the individual queries of a UNION statement in the same order, because UNION compares the expressions one to one in the order given in the individual queries in the SELECT clauses.

Multiple unions

You can string several UNION operations together, as in the following example:
SELECT city AS Cities FROM contact UNION SELECT city FROM customer UNION SELECT city FROM employee

Only one ORDER BY clause is permitted, at the end of the statement. That is, no individual SELECT statement in a UNION query may contain an ORDER BY clause. ♦
Column headings

The column names in the table resulting from a UNION are taken from the first individual query in the statement. If you want to define a new column heading for the result set, you must do so in the first query, as in the following example:
SELECT city AS Cities FROM contact UNION SELECT city FROM customer

In the following query, the column heading remains as city, as it is defined in the first query of the UNION statement.
SELECT city FROM contact UNION SELECT city AS Cities FROM customer

You can use a single ORDER BY clause at the end of the list of queries, but you must use integers rather than column names, as in the following example:
SELECT Cities = city FROM contact UNION SELECT city FROM customer ORDER BY 1

191

Standards and compatibility

Standards and compatibility
This section describes standards and compatibility aspects of the Adaptive Server Anywhere GROUP BY clause.

GROUP BY and the SQL/92 standard
The SQL/92 standard for GROUP BY requires the following: ♦ A column used in an expression of the SELECT clause must be in the GROUP BY clause. Otherwise, the expression using that column is an aggregate function. A GROUP BY expression can only contain column names from the select list, but not those used only as arguments for vector aggregates.

The results of a standard GROUP BY with vector aggregate functions produce one row with one value per group. Adaptive Server Anywhere and Adaptive Server Enterprise support extensions to HAVING that allow aggregate functions not in the select list and not in the GROUP BY clause.

Compatibility with Adaptive Server Enterprise
Adaptive Server Enterprise supports several extensions to the GROUP BY clause that are not supported in Adaptive Server Anywhere. These include the following: ♦
Non-grouped columns in the select list Adaptive Server Enterprise permits column names in the select list that do not appear in the group by clause. For example, the following is valid in Adaptive Server Enterprise: SELECT name, unit_price FROM product GROUP BY name

This syntax is not supported in Adaptive Server Anywhere. ♦
Nested aggregate functions

The following query, which nests a vector aggregate inside a scalar aggregate, is valid in Adaptive Server Enterprise but not in Adaptive Server Anywhere:
SELECT MAX(AVG(unit_price)) FROM product GROUP BY name

192

Chapter 6 Summarizing, Grouping, and Sorting Query Results
♦ ♦
GROUP BY and ALL

Adaptive Server Anywhere does not support the use of ALL in the GROUP BY clause.

HAVING with no GROUP BY Adaptive Server Anywhere does not support the use of HAVING with no GROUP BY clause unless all the expressions in the select and having clauses are aggregate functions. For example, the following query is supported in Adaptive Server Anywhere because the functions MAX and COUNT are aggregate functions: SELECT MAX(unit_price) FROM product HAVING COUNT(*) > 8;

HAVING conditions

Adaptive Server Enterprise supports extensions to HAVING that allow non-aggregate functions not in the select list and not in the GROUP BY clause. Only aggregate functions of this type are allowed in Adaptive Server Anywhere.

DISTINCT with ORDER BY or GROUP BY Adaptive Server Enterprise permits the use of columns in the ORDER BY or GROUP BY clause that do not appear in the select list, even in SELECT DISTINCT queries. This can lead to repeated values in the SELECT DISTINCT result set. Adaptive Server Anywhere does not support this behavior. Column names in UNIONS

Adaptive Server Enterprise permits the use of columns in the ORDER BY clause in unions of queries. In Adaptive Server Anywhere, the ORDER BY clause must use an integer to mark the column by which the results are being ordered.

193

Standards and compatibility

194

C H A P T E R

7

Joins: Retrieving Data from Several Tables

About this chapter

When you create a database, you normalize the data by placing information specific to different objects in different tables, rather than in one large table with many redundant entries. A join operation recreates a larger table using the information from two or more tables (or views). Using different joins, you can construct a variety of these virtual tables, each suited to a particular task.

Before your start

This chapter assumes some knowledge of queries and the syntax of the select statement. Information about queries appears in "Queries: Selecting Data from a Table" on page 149.
Topic How joins work How joins are structured Key joins Natural joins Joins using comparisons Inner, left-outer, and right-outer joins Self-joins and correlation names Cross joins How joins are processed Joining more than two tables Joins involving derived tables Transact-SQL outer joins Page 196 198 200 202 203 205 209 211 214 216 219 220

Contents

195

How joins work

How joins work
A relational database stores information about different types of objects in different tables. For example, information particular to employees appears in one table, and information that pertains to departments in another. The employee table contains information such as an employee’s name and address. The department table contains information about one department, such as the name of the department and who the department head is. Most questions can only be answered using a combination of information from the various tables. For example, you may want to answer the question "Who manages the Sales department?" To find the name of this person, you must identify the correct person using information from the department table, then look up that person’s name in the employee table. Joins are a means of answering such questions by forming a new virtual table that includes information from multiple tables. For example, you could create a list of the department heads by combining the information contained in the employee table and the department table. You specify which tables contain the information you need using the FROM clause. To make the join useful, you must combine the correct columns of each table. To list department heads, each row of the combined table should contain the name of a department and the name of the employee who manages it. You control how columns are matched in the composite table either by specifying a particular type of join operation or by using the ON phrase.

Joins and the relational model
The join operation is the hallmark of the relational model of database management. More than any other feature, the join distinguishes relational database management systems from other types of database management systems. In structured database management systems, often known as network and hierarchical systems, relationships between data values are predefined. Once a database has been set up, it is difficult to make queries about unanticipated relationships among the data. In a relational database management system, on the other hand, relationships among data values are left unstated in the definition of a database. They become explicit when you manipulate the data — for example, when you query the database — not when you create it. You can ask any question that comes to mind about the data stored in the database, regardless of what your intentions were when the database was set up. 196

Chapter 7 Joins: Retrieving Data from Several Tables
According to the rules of good database design, called normalization rules, each table should describe one kind of entity—a person, place, event, or thing. That is why, when you want to compare information about two or more kinds of entities, you need the join operation. You discover relationships among data stored in different tables by joining the different tables. A corollary of this rule is that the join operation gives you unlimited flexibility in adding new kinds of data to your database. You can always create a new table that contains data about a different kind of entity. If the new table has a field with values similar to those in some field of an existing table or tables, it can be linked to those other tables by joining.

197

How joins are structured

How joins are structured
A join operation may appear within a variety of statements, such as within the FROM clause of a SELECT statement. The columns named after the FROM keyword are the columns to be included in the query results, in the desired order. When two or more tables contain a column with the same name, for example, if the product table and the sales_order_items table in the sample database both contain a column named id, you must qualify the column name explicitly to avoid ambiguity. If only one table uses a particular column name, the column name alone suffices.
SELECT product.id, sales_order_items.id, size FROM …

You do not have to qualify the column name size because there is no ambiguity about the table to which it belongs. However, these qualifiers often make your statement clearer, so it is a good idea to get in the habit of including them. As in any SELECT statement, column names in the select list and table names in the FROM clause must be separated by commas.

$ For information about queries use a single table, see "Queries:
Selecting Data from a Table" on page 149.

The FROM clause
Use the FROM clause to specify which tables and views to join. You can name any two or more tables or views. Join operators Adaptive Server Anywhere provides four join operations: ♦ ♦ ♦ ♦ key joins natural joins joins using a condition, such as equality cross joins

Key joins, natural joins and joins on a condition may be of type inner, leftouter, or right-outer. These join types differ in the way they treat rows that have no matching row in the other table.

198

Chapter 7 Joins: Retrieving Data from Several Tables

Data types in join columns
The columns being joined must have the same or compatible data types. Use the convert function when comparing columns whose data types cannot be implicitly converted. If the datatypes used in the join are compatible, Adaptive Server Anywhere automatically converts them. For example, Adaptive Server Anywhere converts among any of the numeric type columns, such as INT or FLOAT, and among any of the character type and date columns, such as CHAR or VARCHAR.

$ For the details of datatype conversions, see "Data type conversions" on
page 293 of the book ASA Reference.

199

Key joins

Key joins
The simplest way to join tables is to connect them using the foreign key relationships built into the database. This method is particularly economical in syntax and especially efficient. Answer the question, "Which orders has Beth Reiser placed?"
SELECT customer.fname, customer.lname, sales_order.id, sales_order.order_date FROM customer KEY JOIN sales_order WHERE customer.fname = ’Beth’ AND customer.lname = ’Reiser’ fname Beth Beth Beth Beth Beth Beth Beth lname Reiser Reiser Reiser Reiser Reiser Reiser Reiser id 2142 2318 2338 2449 2562 2585 2002 order_date 1993-01-22 1993-09-04 1993-09-24 1993-12-14 1994-03-17 1994-04-08 1993-03-20

Use the key join wherever possible. A key join is valid if and only if exactly one foreign key is identified between the two tables. Otherwise, an error indicating the ambiguity results. Some constraints on these joins mean that they will not always be an available option. ♦ ♦ A foreign-key relationship must exist in the database. You cannot use a key join to join two tables that are not related through a foreign key. Only one foreign key relationship can exist between the two tables. If more than one such relationship exists, Adaptive Server Anywhere cannot decide which relationship to use and generates an error indicating the ambiguity. You cannot specify the suitable foreign key in your statement since the syntax of the SQL language does not provide a means to do so. A suitable foreign key relationship must exist. You may need to create a join using particular columns. A foreign-key relationship between the two tables may not suit your purpose.

200

Chapter 7 Joins: Retrieving Data from Several Tables

Key joins are the default

Key join is the default join type in Adaptive Server Anywhere. Anywhere performs a key join if you do not specify the type of join explicitly, using a keyword such as KEY or NATURAL, or by including an ON phrase. For example, Adaptive Server Anywhere performs a key join when it encounters the following statement.
SELECT * FROM product JOIN sales_order_items

Similarly, the following join fails because there are two foreign key relationships between these tables.
SELECT * FROM employee JOIN department

201

Natural joins

Natural joins
A natural join matches the rows from two tables by comparing the values from columns, one in each table, that have the same name. It restricts the results by comparing the values of columns in the two tables with the same column name. An error results if there is no common column name. For example, you can join the employee and department tables using a natural join because they have only one column name in common, namely the dept_id column.
SELECT emp_fname, emp_lname, dept_name FROM employee NATURAL JOIN department ORDER BY dept_name, emp_lname, emp_fname Emp_fname Janet Kristen James Jo Ann Denis Julie John Jennifer Mary Anne Alex Irene Barbara emp_lname Bigelow Coe Coleman Davidson Higgins Jordan Letiecq Litton Shea Ahmed Barletta Blaikie dept_name Finance Finance Finance Finance Finance Finance Finance Finance Finance Marketing Marketing Marketing

202

Chapter 7 Joins: Retrieving Data from Several Tables

Joins using comparisons
You can create a join using a join condition instead of using a KEY or NATURAL join. You specify a join condition by inserting an ON phrase immediately adjacent to the join to which it applies. Natural joins and key joins use generated join conditions; that is, the keyword KEY or NATURAL indicates a restriction on the join results. For a natural join, the generated join condition is based on the names of columns in the tables being joined. For a key join, the condition is based on a foreign key relationship between the two tables. In the sample database, the following are logically equivalent:
SELECT * FROM sales_order JOIN customer ON sales_order.cust_id = customer.id SELECT * FROM sales_order KEY JOIN customer

The first uses a join condition, the second a KEY join. The following two are also equivalent:
SELECT * FROM department JOIN employee ON department.dept_id = employee.dept_id SELECT * FROM department NATURAL JOIN employee

When you join two tables, the columns you compare must have the same or compatible data types. Join types There are several types of join conditions. The most common condition, the equijoin, is based on equality. The following query lists each order number and the name of the customer who placed the order.
SELECT sales_order.id, customer.fname, customer.lname FROM sales_order JOIN customer ON sales_order.cust_id = customer.id

The condition for joining the values in two columns does not need to be equality (=). You can use any of the other comparison operators: not equal (<>), greater than (>), less than (<), greater than or equal to (>=), and less than or equal to (<=).

$ For more information about join types, see "Comparison operators" on
page 225 of the book ASA Reference.

203

Joins using comparisons

Using the WHERE clause in join statements
You can use the WHERE clause to determine which rows to include in the results. In this role, the WHERE clause acts exactly as it does when using a single table, selecting only the rows that interest you. The WHERE clause can also specify the connection between the tables and views named in the FROM clause. In this role, it acts somewhat like the ON phrase. In fact in the case of inner joins, the behavior is identical. However, in outer joins, the same condition can produce different results if moved from an ON phrase to the WHERE clause, because null values are treated differently in these two contexts. The ON phrase allows you to isolate the join constraints and can make your join statement easier to read.

204

Chapter 7 Joins: Retrieving Data from Several Tables

Inner, left-outer, and right-outer joins
Inner joins and outer joins differ in their treatment of rows that have no match in the other table: rows appear in an inner join only if both tables contain at least one row that satisfies the join condition. Because inner joins are the default, you do not need to specify the INNER keyword explicitly. Should you wish to use it for clarity, place it immediately before the JOIN keyword. For example, each row of
SELECT fname, lname, order_date FROM customer KEY INNER JOIN sales_order ORDER BY order_date

contains the information from one customer row and one sales_order row, satisfying the KEY join condition. If a particular customer has placed no orders, the join will contain no information about that customer.
Fname Hardy Tommie Aram Alfredo Elmo Malcolm Lname Mums Wooten Najarian Margolis Smythe Naddem order_date 1993-01-02 1993-01-03 1993-01-03 1993-01-06 1993-01-06 1993-01-07

Because inner joins are the default, you obtain the same result using the following clause.
FROM customer JOIN sales_order

By contrast, an outer join contains rows whether or not a row exists in the opposite table to satisfy the join condition. Use the keywords LEFT or RIGHT to identify the table that is to appear in its entirety. ♦ ♦ A LEFT OUTER JOIN contains every row in the left-hand table. A RIGHT OUTER JOIN contains every row in the right-hand table.

For example, the outer join

205

Inner, left-outer, and right-outer joins
SELECT fname, lname, order_date FROM customer KEY LEFT OUTER JOIN sales_order ORDER BY order_date

includes all customers, whether or not they have placed an order. If a particular customer has placed no orders, each column in the join corresponding to order information contains the NULL value.
Fname Lewis N. Jack Jane John Dominic Stanley Harry Marie Elizibeth Len Tony Tom Janice Stevie Philipe Jennifer William Hardy Tommie Aram … lname Clark Johnson Doe Glenn Johansen Jue Jones Curie Bordon Manager Antolini Cruz O Toole Nickolas Fernandez Stutzman Thompson Mums Wooten Najarian … order_date (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) (NULL) 1993-01-02 1993-01-03 1993-01-03 …

The keywords INNER, LEFT OUTER, and RIGHT OUTER may appear as modifiers in key joins, natural joins, and joins that use a comparison. These modifiers do not apply to cross joins.

206

Chapter 7 Joins: Retrieving Data from Several Tables

Outer joins and join conditions
A common mistake is to place a join condition, which should appear in an ON phrase, in a WHERE clause. Here, the same condition often produces different results. This difference is best explained through a conceptual explanation of the way Adaptive Server Anywhere processes a select statement. 1 First, Adaptive Server Anywhere logically completes all joins. When doing so, it uses only conditions placed within an ON phrase. When the values in one table are missing or null-valued, the behavior depends upon the type of join: inner, left-outer, or right-outer. Once the join is complete, Adaptive Server Anywhere logically deletes those rows for which the condition within the WHERE clause evaluates to either FALSE or UNKNOWN.

2

Because conditions in an ON phrase are treated differently than those in a WHERE clause, moving a condition from one to the other usually converts the join to an inner join, regardless of the type of join specified. With INNER JOINS, specifying a join condition is equivalent to adding the join condition to the WHERE clause. However, the same is not true for OUTER JOINS. For example, the following statement causes a left-outer join.
SELECT * FROM customer LEFT OUTER JOIN sales_order ON customer.id = sales_order.cust_id

In contrast, the following two statements both create inner joins and select the same set of rows.
SELECT * FROM customer KEY LEFT OUTER JOIN sales_order WHERE customer.id = sales_order.cust_id SELECT * FROM customer INNER JOIN sales_order ON customer.id = sales_order.cust_id

The first of these two statements can be thought of as follows: First, leftouter join the customer table to the sales_order table. For those customers who have not yet placed an order, fill the sales order fields with nulls. Next, select those rows in which the customer id values are equal. For those customers who have not placed orders, these values will be NULL. Since comparing any value to NULL results in the special value UNKNOWN, these rows are eliminated and the statement reduces to an inner join.

207

Inner, left-outer, and right-outer joins

$ This methodology describes the logical effect of the statements you type, not how Adaptive Server Anywhere goes about processing them. For further information, see "How joins are processed" on page 214.

208

Chapter 7 Joins: Retrieving Data from Several Tables

Self-joins and correlation names
Joins can compare values within the same column, or two different columns of a single table. These joins are called self-joins. For example, you can create a list of all the employees and the name of each person’s manager by joining the employee table to itself. In such a join, you cannot distinguish the columns by the conventional means because the join contains two copies of every column. For example, suppose you want to create a table of employees that includes the names of their managers. The following query is syntactically incorrect and does not answer this question.
SELECT * FROM employee JOIN employee ON employee.manager_id = employee.emp_id

Use correlation names to distinguish instances of a table

To distinguish an individual instance of a table, use a correlation name. A correlation name is an alias for an instance of a table or view. You define a correlation name in the FROM clause. Once defined, you must use the correlation name in place of the table name elsewhere within your statement, including the selection list, wherever you refer to that instance of the table. The following statement uses the correlation names report and manager to distinguish the two instances of the employee table and so correctly creates the list of employees and their managers.
SELECT report.emp_fname, report.emp_lname, manager.emp_fname, manager.emp_lname FROM employee AS report JOIN employee AS manager ON report.manager_id = manager.emp_id ORDER BY report.emp_lname, report.emp_fname

This statement produces the result shown partially below. The employee names appear in the two left-hand columns and the names of their managers on the right.
Emp_fname Alex Joseph Irene Jeannette Janet Barbara emp_lname Ahmed Barker Barletta Bertrand Bigelow Blaikie emp_fname Scott Jose Scott Jose Mary Anne Scott emp_lname Evans Martinez Evans Martinez Shea Evans

209

Self-joins and correlation names
Emp_fname Jane Robert Matthew Joyce … emp_lname Braun Breault Bucceri Butterfield … emp_fname Jose David Scott Scott … emp_lname Martinez Scott Evans Evans …

Using correlation names

Choose short, concise correlation names to make your statements easier to read. In many cases, names only one or two characters in length suffice. While you must use correlation names for a self-join to distinguish multiple instances of a table, they can make many other statements more readable too. For example, the statement
SELECT customer.fname, customer.lname, sales_order.id, sales_order.order_date FROM customer KEY JOIN sales_order WHERE customer.fname = ’Beth’ AND customer.lname = ’Reiser’

becomes more compact if you use the correlation name c for customer and so for sales_order:
SELECT c.fname, c.lname, so.id, so.order_date FROM customer AS c KEY JOIN sales_order AS so WHERE c.fname = ’Beth’ AND c.lname = ’Reiser’

For brevity, you can even eliminate the keyword AS. It is redundant because the syntax of the SQL language identifies the correlation names: they are separated from the corresponding table name by only a space, not a comma.
SELECT c.fname, c.lname, so.id, so.order_date FROM customer c KEY JOIN sales_order so WHERE c.fname = ’Beth’ AND c.lname = ’Reiser’

$ For further details of the rules regarding correlation names and
instances of a table within a FROM clause, see "Joining more than two tables" on page 216.

210

Chapter 7 Joins: Retrieving Data from Several Tables

Cross joins
As for other types of joins, each row in a cross join is a combination of one row from the first table and one row from the second table. Unlike other joins, a cross join contains no restrictions. All possible combinations of rows are present. Each row of the first table appears exactly once with each row of the second table. Hence, the number of rows in the join is the product of the number of rows in the individual tables. Inner and outer modifiers do not apply to cross joins Except in the presence of additional restrictions in the WHERE clause, all rows of both tables always appear in the result. Thus, the keywords INNER, LEFT OUTER and RIGHT OUTER are not applicable to cross joins. The query
SELECT * FROM table1 CROSS JOIN table2

has a result set as follows: ♦ As long as table1 is not the same name as table2: ♦ ♦ A row in the result set includes all columns in table1 and all columns in table2. There is one row in the result set for each combination of a row in table1 and a row in table2. If table1 has n rows and table2 has n rows, the query returns n x m rows.

If table1 is the same table as table2, and neither is given a correlation name, the result set is simply the rows of table1.

Self-joins and cross joins
The following self-join produces a list of pairs of employees. Each employee name appears in combination with every employee name.
SELECT a.emp_fname, a.emp_lname, b.emp_fname, b.emp_lname FROM employee AS a CROSS JOIN employee AS b

211

Cross joins

Emp_fname Fran Matthew Philip Julie Robert Melissa Jeannette

emp_lname Whitney Cobb Chin Jordan Breault Espinoza Bertrand

Emp_fname Fran Fran Fran Fran Fran Fran Fran

emp_lname Whitney Whitney Whitney Whitney Whitney Whitney Whitney

Since the employee table has 75 rows, this join contains 75 x 75 = 5625 rows. It includes, as well, rows that list each employee with themselves. For example, it contains the row
emp_fname Fran emp_lname Whitney emp_fname Fran emp_lname Whitney

If you want to exclude these rows, use the following command.
SELECT a.emp_fname, a.emp_lname, b.emp_fname, b.emp_lname FROM employee AS a CROSS JOIN employee AS b WHERE a.emp_id !=b.emp_id

Without these rows, the join contains 75 x 74 = 5550 rows. This new join contains rows that pair each employee with every other employee, but because each pair of names can appear in two possible orders, each pair appears twice. For example, the result of the above join contains the following two rows.
emp_fname Matthew Fran emp_lname Cobb Whitney emp_fname Fran Matthew emp_lname Whitney Cobb

If the order of the names is not important, you can produce a list of the (75 x 74)/2 = 2775 unique pairs.
SELECT a.emp_fname, a.emp_lname, b.emp_fname, b.emp_lname FROM employee AS a CROSS JOIN employee AS b WHERE a.emp_id < b.emp_id

212

Chapter 7 Joins: Retrieving Data from Several Tables
This statement eliminates duplicate lines by selecting only those rows in which the emp_id of employee a is less than that of employee b.

$ For more information, see "Self-joins and correlation names" on
page 209.

213

How joins are processed

How joins are processed
Knowing how joins are processed helps to understand them—and to figure out why, when you incorrectly state a join, you sometimes get unexpected results. This section describes the processing of joins in conceptual terms. When executing your statements, Adaptive Server Anywhere uses a sophisticated strategy to obtain the same results by more efficient means. 1 Processing a join uses the FROM clause to form the Cartesian product of the tables—all the possible combinations of the rows from each of the tables. The number of rows in a Cartesian product is the product of the number of rows in the individual tables. This Cartesian product contains rows composed of all columns from all tables. Next, select the rows you want using conditions in the WHERE clause. Whereas you may include NULL values for missing rows using a left- or right-outer join, Adaptive Server Anywhere selects rows only if the conditions evaluate to TRUE. It omits rows if the conditions evaluate to either FALSE or UNKNOWN. If you include a GROUP BY clause, the rows are partitioned according to your conditions. Next, rows are selected from these partitions according to any conditions in the HAVING clause. If the statement includes an ORDER BY clause, then Adaptive Server Anywhere uses it to order the remaining rows. When you do not specify an ordering, make no assumptions regarding the order of the rows. Finally, Adaptive Server Anywhere returns those columns you specified in your select statement.
Tips

2

3

4

5

Adaptive Server Anywhere accepts a wide range of syntax. This flexibility means that most queries result in an answer, but sometimes not the one you intended. The following precautions may help you avoid this peril. 1 Always use correlation names. 2 Try eliminating a WHERE clause when testing a new statement. 3 Avoid mixing inner joins with left-outer or right-outer joins. 4 Examine the plan for your query—does it include all the tables?

214

Chapter 7 Joins: Retrieving Data from Several Tables

Performance considerations
Generally, Adaptive Server Anywhere prefers to process joins by selecting information in one table, then performing an indexed look-up to get the rows it needs from another. Anywhere carefully optimizes each of your statements before executing it. As long as your statement correctly identifies the information you want, it usually doesn’t matter what syntax you use. In particular, Adaptive Server Anywhere is free to reconstruct your statement to any form that is semantically equivalent. It almost always does so, to help compute your result efficiently. You can determine the result of a statement using the above methods, but Anywhere usually obtains the result by another means. Adaptive Server Anywhere improves performance using indexes whenever doing so improves performance. Columns that are part of a primary or secondary key are indexed automatically. Other columns are not. Creating additional indexes on columns involved in a join, either as part of a join condition or in a where clause, can improve performance dramatically.

$ For further performance tips, see "Monitoring and Improving
Performance" on page 799.

215

Joining more than two tables

Joining more than two tables
To carry out many queries, you need to join more than two tables. Here, you have two options at your disposal. The following statement answers the question "What items are listed on order number 2015?"
SELECT product.name, size, sales_order_items.quantity FROM sales_order KEY JOIN sales_order_items KEY JOIN product WHERE sales_order.id = 2015 id 300 301 302 700 Name Tee Shirt Tee Shirt Tee Shirt Shorts size Small Medium One size fits all Medium quantity 24 24 24 24

When you want to join a number of tables sequentially, the above syntax makes a lot of sense. However, sometimes you need to join a single table to several others that surround it.

Star joins
Some joins must join a single table to several others around it. This type of join is called a star join. As an example, create a list the names of the customers who have placed orders with Rollin Overbey.
SELECT c.fname, c.lname, o.order_date FROM sales_order AS o KEY JOIN customer AS c, sales_order AS o KEY JOIN employee AS e WHERE e.emp_fname = ’Rollin’ AND e.emp_lname = ’Overbey’ ORDER BY o.order_date

Notice that one of the tables in the FROM clause, employee, does not contribute any columns to the results. Nor do any of the columns that are joined—such as customer.id or employee.id—appear in the results. Nonetheless, this join is possible only using the employee table in the FROM clause.

216

Chapter 7 Joins: Retrieving Data from Several Tables

Fname Tommie Michael Salton Tommie Michael

lname Wooten Agliori Pepper Wooten Agliori

order_date 1993-01-03 1993-01-08 1993-01-17 1993-01-23 1993-01-24

The following statement uses a star join around the sales_order table. The result is a list showing all the customers and the total quantity of each type of product they have ordered. Some customers have not placed orders, so the other values for these customers are NULL. In addition, it shows the name of the manager of the sales person through whom they placed the orders.
SELECT c.fname, p.name, SUM(i.quantity), m.emp_fname FROM sales_order o KEY LEFT OUTER JOIN sales_order_items i KEY LEFT OUTER JOIN product p, customer c, sales_order o KEY LEFT OUTER JOIN employee e LEFT OUTER JOIN employee m ON e.manager_id = m.emp_id WHERE c.state = ’CA’ GROUP BY c.fname, p.name, m.emp_fname ORDER BY SUM(i.quantity) DESC, c.fname

Note the following details of this statement: ♦ ♦ ♦ ♦ The join centers on the sales_order table. The keyword AS is optional and has been omitted. All joins must be outer joins to keep in the result set the customers who haven’t placed any orders. The condition e.manager_id = m.emp_id must be placed in the ON clause instead of the WHERE clause. The result of this statement would be inner join if this condition moved into the WHERE clause. The query is syntactically correct in Adaptive Server Anywhere only if the EXTENDED_JOIN_SYNTAX option is ON.

$ For more information about the EXTENDED_JOIN_SYNTAX option,
see "Database Options" on page 155 of the book ASA Reference. The statement produces the results partially shown in the table below.

217

Joining more than two tables

Fname Harry Jane Philipe Sheng Laura Moe Leilani Almen …

name (NULL) (NULL) (NULL) Baseball Cap Tee Shirt Tee Shirt Sweatshirt Baseball Cap …

SUM(i.quantity) (NULL) (NULL) (NULL) 240 192 192 132 108 …

emp_fname (NULL) (NULL) (NULL) Moira Moira Moira Moira Moira …

218

Chapter 7 Joins: Retrieving Data from Several Tables

Joins involving derived tables
You can nest queries within a FROM clause in derived tables. Using derived tables, you can perform grouping of groups or construct a join with a group, without having to create a view. In the following example, the inner SELECT statement (enclosed in parentheses) creates a derived table, grouped by customer id values. The outer SELECT statement assigns this table the correlation name sales_order_counts and joins it to the customer table using a join condition.
SELECT lname, fname, number_of_orders FROM customer join ( SELECT cust_id, count(*) FROM sales_order GROUP BY cust_id ) AS sales_order_counts (cust_id, number_of_orders) ON (customer.id = sales_order_counts.cust_id) WHERE number_of_orders > 3

The result is a table of the names of those customers who have placed more than three orders, including the number of orders each has placed.

219

Transact-SQL outer joins

Transact-SQL outer joins
Joins that include all rows, regardless of whether or not they match the join condition, are called outer joins. Adaptive Server Anywhere supports both left and right outer joins via the LEFT OUTER and RIGHT OUTER keywords. For compatibility with Adaptive Server Enterprise, Anywhere supports the Transact-SQL-language counterparts of these keywords. In the Transact-SQL dialect, you create joins by separating table names with commas in the FROM clause. The join conditions appear in the WHERE clause, rather than in the ON phrase. Special conditional operators indicate the type of join.

Transact-SQL left-outer joins
The left outer join operator, *=, selects all rows from the left hand table that meet the statement’s restrictions. The right hand table generates values if there is a match on the join condition. Otherwise, the second table generates null values. For example, the following left outer join lists all customers and finds their order dates (if any):
SELECT fname, lname, order_date FROM customer, sales_order WHERE customer.id *= sales_order.cust_id ORDER BY order_date

Preserved and null-supplying tables

For an outer join, a table is either preserved or null-supplying. If the join operator is *=, the second table is the null-supplying table; if the join operator is =*, the first table is the null-supplying table. In addition to using it in the outer join, you can compare a column from the preserved table to a constant. For example, you can use the following statement to find information about customers in California.
SELECT fname, lname, order_date FROM customer, sales_order WHERE customer.state = ’CA’ AND customer.id *= sales_order.cust_id ORDER BY order_date

However, the null-supplying table in a Transact-SQL outer join cannot also participate in another regular or outer join.

220

Chapter 7 Joins: Retrieving Data from Several Tables
Bit columns

Since bit columns do not permit null values, a value of 0 appears in an outer join when the bit column is in the null-supplying table, and this table generates NULL values.

Transact-SQL right-outer joins
The right outer join, =*, selects all rows from the second table that meet the statement’s restrictions. The first table generates values if there is a match on the join condition. Otherwise, the first table generates null values. The right outer join is specified with the comparison operator =*, which indicates that all the rows in the second table are to be included in the results, regardless of whether there is matching data in the first table. Substituting this operator in the outer join query shown earlier gives this result:
SELECT fname, lname, order_date FROM sales_order, customer WHERE sales_order.cust_id =* customer.id ORDER BY order_date

Transact-SQL outer join restrictions
There are several restrictions for Transact-SQL outer joins: ♦ You cannot mix SQL/92 syntax and Transact-SQL outer join syntax in a single query. This applies to views used by a query also: if a view is defined using one dialect for an outer join, you must use the same dialect for any outer-join queries on that view. A null-supplying table cannot participate in both a Transact-SQL outer join and a regular join or two outerjoins. For example, the following WHERE clause is not allowed:
WHERE R.x *= S.x AND S.y = T.y

When you cannot rewrite your query to avoid using a table in both an outer join and a regular join clause, you must divide your statement into two separate queries, or use only SQL/92 syntax. ♦ You cannot use a subquery that contains a join condition involving the null-supplying table of an outer join. For example, the following WHERE clause is not allowed:
WHERE R.x *= S.y

221

Transact-SQL outer joins
AND EXISTS ( SELECT * FROM T WHERE T.x = S.x )

If you submit a query with an outer join and a qualification on a column from the null-supplying table of the outer join, the results may not be what you expect. The qualification in the query does not restrict the number of rows returned, but rather affects which rows in the result set contain the null value. For rows that do not meet the qualification, a null value appears in the null-supplying table’s columns of those rows.

Views used with Transact-SQL outer joins
If you define a view with an outer join, and then query the view with a qualification on a column from the null-supplying table of the outer join, the results may not be what you expect. The query returns all rows from the nullsupplying table. Rows that do not meet the qualification show a NULL value in the appropriate columns of those rows. The following rules determine what types of updates you can make to columns through views that contain outer joins: ♦ ♦ INSERT and DELETE statements are not allowed on outer join views. UPDATE statements are allowed on outer join views. If the view is defined WITH CHECK option, the update fails if any of the affected columns appears in the WHERE clause in an expression that includes columns from more than one table.

How NULL affects Transact-SQL joins
NULL values in tables or views being joined will never match each other. Since bit columns do not permit NULLs, a value of 0 appears in an outer join when the null-supplying table generates NULL rows. The result of comparing a NULL value with any other NULL value is FALSE. Because null values represent unknown or inapplicable values, Transact-SQL has no reason to believe that one unknown value matches another.

222

C H A P T E R

8

Using Subqueries

About this chapter

When you create a query, you use WHERE and HAVING clauses to restrict the rows the query displays. Sometimes, the rows you select depend on information stored in more than one table. A subquery in the WHERE or HAVING clause allows you to select rows from one table according to specifications obtained from another table. Additional ways to do this can be found in "Joins: Retrieving Data from Several Tables" on page 195

Before your start

This chapter assumes some knowledge of queries and the syntax of the select statement. Information about queries appears in "Queries: Selecting Data from a Table" on page 149.
Topic What is a subquery? Using Subqueries in the WHERE clause Subqueries in the HAVING clause Subquery comparison test Quantified comparison tests with ANY and ALL Testing set membership with IN conditions Existence test Outer references Subqueries and joins Nested subqueries How subqueries work Page 224 225 226 228 230 233 235 237 238 241 243

Contents

223

What is a subquery?

What is a subquery?
A relational database stores information about different types of objects in different tables. For example, you should store information particular to products in one table, and information that pertains to sales orders in another. The product table contains the information about the various products. The sales order items table contains information about customers’ orders. In general, only the simplest questions can be answered using only one table. For example, if the company reorders products when there are fewer than 50 of them in stock, then it is possible to answer the question "Which products are nearly out of stock?" with this query:
SELECT id, name, description, quantity FROM product WHERE quantity < 50

However, if "nearly out of stock" depends on how many items of each type the typical customer orders, the number "50" will have to be replaced by a value obtained from the sales_order_items table. Structure of the subquery A subquery is structured like a regular query, and appears in the main query’s WHERE or HAVING clause. In the above example, for instance, you can use a subquery to select the average number of items that a customer orders, and then use that figure in the main query to find products that are nearly out of stock. The following query finds the names and descriptions of the products which number less than double the average number of items of each type that a customer orders.
SELECT name, description FROM product WHERE quantity < 2 * ( SELECT avg(quantity) FROM sales_order_items )

SQL subqueries always appear in the WHERE or HAVING clauses of the main query. In the WHERE clause, they help select the rows from the tables listed in the FROM clause that appear in the query results. In the HAVING clause, they help select the row groups, as specified by the main query’s GROUP BY clause, that appear in the query results.

224

Chapter 8 Using Subqueries

Using Subqueries in the WHERE clause
Subqueries in the WHERE clause work as part of the row selection process. You use a subquery in the WHERE clause when the criteria you use to select rows depend on the results of another table. Example Find the products whose in-stock quantities are less than double the average ordered quantity.
SELECT name, description FROM product WHERE quantity < 2 * ( SELECT avg(quantity) FROM sales_order_items)

This is a two-step query: first, find the average number of items requested per order; and then find which products in stock number less than double that quantity. The query in two steps The quantity column of the sales_order_items table stores the number of items requested per item type, customer, and order. The subquery is
SELECT avg(quantity) FROM sales_order_items

It returns the average quantity of items in the sales_order_items table, which is the number 25.851413. The next query returns the names and descriptions of the items whose instock quantities are less than twice the previously-extracted value
SELECT name, description FROM product WHERE quantity < 2*25.851413

Using a subquery combines the two steps into a single operation. Purpose of a subquery in the WHERE clause A subquery in the WHERE clause is part of a search condition. The chapter "Queries: Selecting Data from a Table" on page 149 describes simple search conditions you can use in the WHERE clause.

225

Subqueries in the HAVING clause

Subqueries in the HAVING clause
Although you usually use subqueries as search conditions in the WHERE clause, sometimes you can also use them in the HAVING clause of a query. When a subquery appears in the HAVING clause, like any expression in the HAVING clause, it is used as part of the row group selection. Here is a request that lends itself naturally to a query with a subquery in the HAVING clause: "Which products’ average in-stock quantity is less than double the average number of each item ordered per customer?" Example
SELECT name, avg(quantity) FROM product GROUP BY name HAVING avg(quantity) > 2* ( SELECT avg(quantity) FROM sales_order_items ) name Baseball Cap Shorts Tee Shirt avg(quantity) 62.000000 80.000000 52.333333

The query executes as follows: ♦ ♦ ♦ The subquery calculates the average quantity of items in the sales_order_items table. The main query then goes through the product table, calculating the average quantity product, grouping by product name. The HAVING clause then checks if each average quantity is more than double the quantity found by the subquery. If so, the main query returns that row group; otherwise, it doesn’t. The SELECT clause produces one summary row for each group, showing the name of each product and its in-stock average quantity.

You can also use outer references in a HAVING clause, as shown in this request, a slight variation on the one above: Example "Find the product ID numbers and line ID numbers of those products whose average ordered quantities is more than half the in-stock quantities of those products."

226

Chapter 8 Using Subqueries
SELECT prod_id, line_id FROM sales_order_items GROUP BY prod_id, line_id HAVING 2* avg(quantity) > ( SELECT quantity FROM product WHERE product.id = sales_order_items.prod_id) Prod_id 300 401 500 501 600 … line_id 1 2 1 2 1 …

In this example, the subquery must produce the in-stock quantity of the product corresponding to the row group being tested by the HAVING clause. The subquery selects records for that particular product, using the outer reference sales_order_items.prod_id. A subquery with a comparison returns a single value This query uses the comparison ">", suggesting that the subquery must return exactly one value. In this case, it does. Since the id field of the product table is a primary key, there is only one record in the product table corresponding to any particular product id.

Subquery tests
The chapter "Queries: Selecting Data from a Table" on page 149 describes simple search conditions you can use in the HAVING clause. Since a subquery is just an expression that appears in the WHERE or HAVING clauses, the search conditions on subqueries may look familiar. They include: ♦
Subquery comparison test Compares the value of an expression to a single value produced by the subquery for each record in the table(s) in the main query. Quantified comparison test Compares the value of an expression to each of the set of values produced by a subquery. Subquery set membership test Existence test

♦ ♦ ♦

Checks if the value of an expression matches one of the set of values produced by a subquery. Checks if the subquery produces any rows. 227

Subquery comparison test

Subquery comparison test
The subquery comparison test (=, <>, <. <=, >, >=) is a modified version of the simple comparison test; the only difference between the two is that in the former, the expression following the operator is a subquery. This test is used to compare a value from a row in the main query to a single value produced by the subquery. Example This query contains an example of a subquery comparison test:
SELECT name, description, quantity FROM product WHERE quantity < 2 * ( SELECT avg(quantity) FROM sales_order_items) name Tee Shirt Baseball Cap Visor Visor Sweatshirt Sweatshirt description Tank Top Wool cap Cloth Visor Plastic Visor Hooded Sweatshirt Zipped Sweatshirt quantity 28 12 36 28 39 32

The following subquery retrieves a single value – the average quantity of items of each type per customer's order — from the sales_order_items table.
SELECT avg(quantity) FROM sales_order_items

Then the main query compares the quantity of each in-stock item to that value. A subquery in a comparison test returns one value A subquery in a comparison test must return exactly one value. Consider this query, whose subquery extracts two columns from the sales_order_items table:
SELECT name, description, quantity FROM product WHERE quantity < 2 * ( SELECT avg(quantity), max (quantity) FROM sales_order_items)

It returns the error Subquery allowed only one select list item. Similarly, the following query returns multiple values from the quantity column – one for each row in the sales_order_items table. 228

Chapter 8 Using Subqueries
SELECT name, description, quantity FROM product WHERE quantity < 2 * ( SELECT quantity FROM sales_order_items)

It returns the error Subquery cannot return more than one result. The subquery must appear to the right of a comparison operator The subquery comparison test allows a subquery only on the right side of the comparison operator. Thus the comparison
main-query-expression < subquery

is acceptable, but the comparison
subquery < main-query-expression

is not acceptable.

229

Quantified comparison tests with ANY and ALL

Quantified comparison tests with ANY and ALL
The quantified comparison test has two categories, the ALL test and the ANY test:

The ANY test
The ANY test, used in conjunction with one of the SQL comparison operators (=, <>, <, <=, >, >=), compares a single value to the column of data values produced by the subquery. To perform the test, SQL uses the specified comparison operator to compare the test value to each data value in the column. If any of the comparisons yields a TRUE result, the ANY test returns TRUE. A subquery used with ANY must return a single column. Example Find the order and customer ID’s of those orders placed after the first product of the order #2005 was shipped.
SELECT id, cust_id FROM sales_order WHERE order_date > ANY ( SELECT ship_date FROM sales_order_items WHERE id=2005) Id 2006 2007 2008 2009 … Cust_id 105 106 107 108 …

In executing this query, the main query tests the order dates for each order against the shipping dates of every product of the order #2005. If an order date is greater than the shipping date for one shipment of order #2005, then that id and customer id from the sales_order table are part of the result set. The ANY test is thus analogous to the OR operator: the above query can be read, "Was this sales order placed after the first product of the order #2005 was shipped, or after the second product of order #2005 was shipped, or…"

230

Chapter 8 Using Subqueries
The ANY operator can be a bit confusing. It is tempting to read the query as "Return those orders placed after any products of order #2005 were shipped". But this means the query will return the order ID’s and customer ID’s for the orders placed after all products of order #2005 were shipped – which is not what the query does! Instead, try reading the query like this: "Return the order and customer ID's for those orders placed after at least one product of order #2005 was shipped." Using the keyword SOME may provide a more intuitive way to phrase the query. The following query is equivalent to the previous query.
SELECT id, cust_id FROM sales_order WHERE order_date > SOME ( SELECT ship_date FROM sales_order_items WHERE id=2005)

Understanding the ANY operator

The keyword SOME is equivalent to the keyword ANY. Notes about the ANY operator There are two additional important characteristics of the ANY test: ♦
Empty subquery result set If the subquery produces an empty result

set, the ANY test returns FALSE. This makes sense, since if there are no results, then it is not true that at least one result satisfies the comparison test. ♦
NULL values in subquery result set Assume that there is at least one NULL value in the subquery result set. If the comparison test is FALSE for all non-NULL data values in the result set, the ANY search returns FALSE. This is because in this situation, you cannot conclusively state whether there is a value for the subquery for which the comparison test holds. There may or may not be a value, depending on the "correct" values for the NULL data in the result set.

The ALL test
Like the ANY test, the ALL test is used in conjunction with one of the six SQL comparison operators (=, <>, <, <=, >, >=) to compare a single value to the data values produced by the subquery. To perform the test, SQL uses the specified comparison operator to compare the test value to each data value in the result set. If all of the comparisons yield TRUE results, the ALL test returns TRUE. Example Here is a request naturally handled with the ALL test: "Find the order and customer ID's of those orders placed after all products of order #2001 were shipped."

231

Quantified comparison tests with ANY and ALL
SELECT id, cust_id FROM sales_order WHERE order_date > ALL ( SELECT ship_date FROM sales_order_items WHERE id=2001) Id 2002 2003 2004 2005 … cust_id 102 103 104 101 …

In executing this query, the main query tests the order dates for each order against the shipping dates of every product of order #2001. If an order date is greater than the shipping date for every shipment of order #2001, then the id and customer id from the sales_order table are part of the result set. The ALL test is thus analogous to the AND operator: the above query can be read, "Was this sales order placed before the first product of order #2001 was shipped, and before the second product of order #2001 was shipped, and…" Notes about the ALL operator There are three additional important characteristics of the ALL test: ♦
Empty subquery result set If the subquery produces an empty result

set, the ALL test returns TRUE. This makes sense, since if there are no results, then it is true that the comparison test holds for every value in the result set. ♦
NULL values in subquery result set Assume that there is at least one NULL value in the subquery result set. If the comparison test is FALSE for all non NULL data values in the result set, the ALL search returns FALSE. In this situation you cannot conclusively state whether the comparison test holds for every value in the subquery result set; it may or may not, depending on the "correct" values for the NULL data. Negating the ALL test

The following expressions are not equivalent.

NOT a = ALL (subquery)

a <> ALL (subquery)

$ This is explained in detail in "Quantified comparison test" on page 245.

232

Chapter 8 Using Subqueries

Testing set membership with IN conditions
You can use the subquery set membership test to compare a value from the main query to more than one value in the subquery. The subquery set membership test compares a single data value for each row in the main query to the single column of data values produced by the subquery. If the data value from the main query matches one of the data values in the column, the subquery returns TRUE. Example Select the names of the employees who head the Shipping or Finance departments:
SELECT emp_fname, emp_lname FROM employee WHERE emp_id IN ( SELECT dept_head_id FROM department WHERE (dept_name=’Finance’ or dept_name = ’Shipping’)) emp_fname Mary Anne Jose Emp_lname Shea Martinez

The subquery in this example
SELECT dept_head_id FROM department WHERE (dept_name=’Finance’ OR dept_name = ’Shipping’)

extracts from the department table the id numbers that correspond to the heads of the Shipping and Finance departments. The main query then returns the names of the employees whose id numbers match one of the two found by the subquery. Set membership test is equivalent to =ANY test The subquery set membership test is equivalent to the =ANY test. The following query is equivalent to the query from the above example.
SELECT emp_fname, emp_lname FROM employee WHERE emp_id =ANY ( SELECT dept_head_id FROM department WHERE (dept_name=’Finance’ or dept_name = ’Shipping’))

233

Testing set membership with IN conditions

Negation of the set membership test

You can also use the subquery set membership test to extract those rows whose column values are not equal to any of those produced by a subquery. To negate a set membership test, insert the word NOT in front of the keyword IN. The subquery in this query returns the first and last names of the employees that are not heads of the Finance or Shipping departments.
SELECT emp_fname, emp_lname FROM employee WHERE emp_id NOT IN ( SELECT dept_head_id FROM department WHERE (dept_name=’Finance’ OR dept_name = ’Shipping’))

Example

234

Chapter 8 Using Subqueries

Existence test
Subqueries used in the subquery comparison test and set membership test both return data values from the subquery table. Sometimes, however, you may be more concerned with whether the subquery returns any results, rather than which results. The existence test (EXISTS) checks whether a subquery produces any rows of query results. If the subquery produces one or more rows of results, the EXISTS test returns TRUE. Otherwise, it returns FALSE. Example Here is an example of a request expressed using a subquery: "Which customers placed orders after July 13, 1994?"
SELECT fname, lname FROM customer WHERE EXISTS ( SELECT * FROM sales_order WHERE (order_date > ’1994-07-13’) AND (customer.id = sales_order.cust_id)) Fname Grover Ling Ling Bubba Almen lname Pendelton Andrews Murphy de Joie

Explanation of the existence test

Here, for each row in the customer table, the subquery checks if that customer ID corresponds to one that has placed an order after July 13, 1994. If it does, the query extracts the first and last names of that customer from the main table. The EXISTS test does not use the results of the subquery; it just checks if the subquery produces any rows. So the existence test applied to the following two subqueries return the same results:
SELECT * FROM sales_order WHERE (order_date > ’1994-07-13’) AND (customer.id = sales_order.cust_id) SELECT ship_date FROM sales_order WHERE (order_date > ’1994-07-13’) AND (customer.id = sales_order.cust_id)

235

Existence test
It does not matter which columns from the sales_order table appear in the SELECT statement, though by convention, the "SELECT *" notation is used. Negating the existence test Correlated subqueries You can reverse the logic of the EXISTS test using the NOT EXISTS form. In this case, the test returns TRUE if the subquery produces no rows, and FALSE otherwise. You may have noticed that the subquery contains a reference to the id column from the customer table. References to columns or expressions in the main table(s) are called outer references and the subquery is said to be correlated. Conceptually, SQL processes the above query by going through the customer table, and performing the subquery for each customer. If the order date in the sales_order table is after July 13, 1994, and the customer ID in the customer and sales_order tables match, then the first and last names from the customer table appear. Since the subquery references the main query, the subquery in this section, unlike those from previous sections, returns an error if you attempt to run it by itself.

236

Chapter 8 Using Subqueries

Outer references
Within the body of a subquery, it is often necessary to refer to the value of a column in the active row of the main query. Consider the following query:
SELECT name, description FROM product WHERE quantity < 2 * ( SELECT avg(quantity) FROM sales_order_items WHERE product.id = sales_order_items.prod_id)

This query extracts the names and descriptions of the products whose instock quantities are less than double the average ordered quantity of that product — specifically, the product being tested by the WHERE clause in the main query. The subquery does this by scanning the sales_order_items table. But the product.id column in the WHERE clause of the subquery refers to a column in the table named in the FROM clause of the main query — not the subquery. As SQL moves through each row of the product table, it uses the id value of the current row when it evaluates the WHERE clause of the subquery. Description of an outer reference The product.id column in this subquery is an example of an outer reference. A subquery that uses an outer reference is a correlated subquery. An outer reference is a column name that does not refer to any of the columns in any of the tables in the FROM clause of the subquery. Instead, the column name refers to a column of a table specified in the FROM clause of the main query. As the above example shows, the value of a column in an outer reference comes from the row currently being tested by the main query.

237

Subqueries and joins

Subqueries and joins
The subquery optimizer automatically rewrites as joins many of the queries that make use of subqueries. Example Consider the request, "When did Mrs. Clarke and Suresh place their orders, and by which sales representatives?" It can be handled by the following query:
SELECT order_date, sales_rep FROM sales_order WHERE cust_id IN ( SELECT id FROM customer WHERE lname = ’Clarke’ OR fname = ’Suresh’) Order_date 1994-01-05 1993-01-27 1993-11-11 1994-02-04 1994-02-19 1994-04-02 1993-11-09 1994-01-29 1994-05-25 sales_rep 1596 667 467 195 195 299 129 690 299

The subquery yields a list of customer ID’s that correspond to the two customers whose names are listed in the WHERE clause, and the main query finds the order dates and sales representatives corresponding to those two people’s orders. Replacing a subquery with a join The same question can be answered using joins. Here is an alternative form of the query, using a two-table join:
SELECT order_date, sales_rep FROM sales_order, customer WHERE cust_id=customer.id AND (lname = ’Clarke’ OR fname = ’Suresh’)

238

Chapter 8 Using Subqueries
This form of the query joins the sales_order table to the customer table to find the orders for each customer, and then returns only those records for Suresh and Mrs. Clarke. Some joins cannot be written as subqueries Both of these queries find the correct order dates and sales representatives, and neither is more right than the other. Many people will find the subquery form more natural, because the request doesn’t ask for any information about customer ID’s, and because it might seem odd to join the sales_order and customer tables together to answer the question. If, however, the request changes to include some information from the customer table, the subquery form no longer works. For example, the request "When did Mrs. Clarke and Suresh place their orders, and by which representatives, and what are their full names?", it is necessary to include the customer table in the main WHERE clause:
SELECT fname, lname, order_date, sales_rep FROM sales_order, customer WHERE cust_id=customer.id AND (lname = ’Clarke’ OR fname = ’Suresh’) fname Belinda Belinda Belinda Belinda Belinda Suresh Suresh Suresh Suresh Lname Clarke Clarke Clarke Clarke Clarke Naidu Naidu Naidu Naidu order_date 1994-01-05 1993-01-27 1993-11-11 1994-02-04 1994-02-19 1994-04-02 1993-11-09 1994-01-29 1994-05-25 sales_rep 1596 667 467 195 195 299 129 690 299

Some subqueries cannot be written as joins

Similarly, there are cases where a subquery will work but a join will not. For example:
SELECT name, description, quantity FROM product WHERE quantity < 2 * ( SELECT avg(quantity) FROM sales_order_items)

239

Subqueries and joins

Name Tee Shirt Baseball Cap Visor …

Description Tank Top Wool cap Cloth Visor …

quantity 28 12 36 …

In this case, the inner query is a summary query and the outer query is not, so there is no way to combine the two queries by a simple join.

$ For more information on joins, see "Queries: Selecting Data from a
Table" on page 149.

240

Chapter 8 Using Subqueries

Nested subqueries
As we have seen, subqueries always appear in the HAVING clause or the WHERE clause of a query. A subquery may itself contain a WHERE clause and/or a HAVING clause, and, consequently, a subquery may appear in another subquery. Subqueries inside other subqueries are called nested subqueries. Examples List the order IDs and line IDs of those orders shipped on the same day when any item in the fees department was ordered.
SELECT id, line_id FROM sales_order_items WHERE ship_date = ANY ( SELECT order_date FROM sales_order WHERE fin_code_id IN ( SELECT code FROM fin_code WHERE (description = ’Fees’))) Id 2001 2001 2001 2002 2002 … line_id 1 2 3 1 2 …

Explanation of the nested subqueries

In this example, the innermost subquery produces a column of financial codes whose descriptions are "Fees":
SELECT code FROM fin_code WHERE (description = ’Fees’)

The next subquery finds the order dates of the items whose codes match one of the codes selected in the innermost subquery:
SELECT order_date FROM sales_order WHERE fin_code_id IN (subquery)

Finally, the outermost query finds the order ID’s and line ID’s of the orders shipped on one of the dates found in the subquery.

241

Nested subqueries
SELECT id, line_id FROM sales_order_items WHERE ship_date = ANY (subquery)

Nested subqueries can also have more than three levels. Though there is no maximum number of levels, queries with three or more levels take considerably longer to run than do smaller queries.

242

Chapter 8 Using Subqueries

How subqueries work
Understanding which queries are valid and which ones aren’t can be complicated when a query contains a subquery. Similarly, figuring out what a multi-level query does can also be very involved, and it helps to understand how the database server processes subqueries. For general information about processing queries, see "Summarizing, Grouping, and Sorting Query Results" on page 173.

Correlated subqueries
In a simple query, the database server evaluates and processes the query’s WHERE clause once for each row of the query. Sometimes, though, the subquery returns only one result, making it unnecessary for the database server to evaluate it more than once for the entire result set. Uncorrelated subqueries Consider this query:
SELECT name, description FROM product WHERE quantity < 2 * ( SELECT avg(quantity) FROM sales_order_items)

In this example, the subquery calculates exactly one value: the average quantity from the sales_order_items table. In evaluating the query, the database server computes this value once, and compares each value in the quantity field of the product table to it to determine whether to select the corresponding row. Correlated subqueries When a subquery contains an outer reference, you cannot use this shortcut. For instance, the subquery in the query
SELECT name, description FROM product WHERE quantity < 2 * ( SELECT avg(quantity) FROM sales_order_items WHERE product.id=sales_order_items.prod_id)

returns a value dependent upon the active row in the product table. Such subqueries are called correlated subqueries. In these cases, the subquery might return a different value for each row of the outer query, making it necessary for the database server to perform more than one evaluation.

243

How subqueries work

Converting subqueries in the WHERE clause to joins
In general, a query using joins executes faster than a multi-level query. For this reason, whenever possible, the Adaptive Server Anywhere query optimizer converts a multi-level query to a query using joins. The conversion is carried out without any user action. This section describes which subqueries can be converted to joins so you can understand the performace of queries in your database. Example The question "When did Mrs. Clarke and Suresh place their orders, and by which sales representatives?" can be written as a two-level query:
SELECT order_date, sales_rep FROM sales_order WHERE cust_id IN ( SELECT id FROM customer WHERE lname = ’Clarke’ OR fname = ’Suresh’)

An alternate, and equally correct way to write the query uses joins:
SELECT fname, lname, order_date, sales_rep FROM sales_order, customer WHERE cust_id=customer.id AND (lname = ’Clarke’ OR fname = ’Suresh’)

The criteria that must be satisfied in order for a multi-level query to be able to be rewritten with joins differ for the various types of operators. Recall that when a subquery appears in the query’s WHERE clause, it is of the form
SELECT select-list FROM table WHERE [NOT] expression comparison-operator (subquery) | [NOT] expression comparison-operator ANY / SOME (subquery) | [NOT] expression comparison-operator ALL (subquery) | [NOT] expression IN (subquery) | [NOT] EXISTS (subquery) GROUP BY group-by-expression HAVING search-condition

Whether a subquery can be converted to a join depends on a number of factors, such as the type of operator and the structures of the query and of the subquery.

244

Chapter 8 Using Subqueries

Comparison operators
A subquery that follows a comparison operator (=, <>, <, <=, >, >=) must satisfy certain conditions if it is to be converted into a join. Subqueries that follow comparison operators in general are valid only if they return exactly one value for each row of the main query. In addition to this criterion, a subquery is converted to a join only if the subquery ♦ ♦ ♦ ♦ Example does not contain a GROUP BY clause does not contain the keyword DISTINCT is not a UNION query is not an aggregate query

Suppose the request "When were Suresh’s products ordered, and by which sales representative?" were phrased as the subquery
SELECT order_date, sales_rep FROM sales_order WHERE cust_id = ( SELECT id FROM customer WHERE fname = ’Suresh’)

This query satisfies the criteria, and therefore, it would be converted to a query using a join:
SELECT order_date, sales_rep FROM sales_order, customer WHERE cust_id=customer.id AND (lname = ’Clarke’ OR fname = ’Suresh’)

However, the request, "Find the products whose in-stock quantities are less than double the average ordered quantity" cannot be converted to a join, as the subquery contains the aggregate function avg:
SELECT name, description FROM product WHERE quantity < 2 * ( SELECT avg(quantity) FROM sales_order_items)

Quantified comparison test
A subquery that follows one of the keywords ALL, ANY and SOME is converted into a join only if it satisfies certain criteria. ♦ The main query does not contain a GROUP BY clause, and is not an aggregate query, or the subquery returns exactly one value. 245

How subqueries work
♦ ♦ ♦ ♦ ♦ ♦ The subquery does not contain a GROUP BY clause. The subquery does not contain the keyword DISTINCT. The subquery is not a UNION query. The subquery is not an aggregate query. The conjunct ’expression comparison-operator ANY/SOME (subquery)’ must be negated. The conjunct ’expression comparison-operator ALL (subquery)’ must not be negated.

The first four of these conditions are relatively straightforward. Example The request "When did Ms. Clarke and Suresh place their orders, and by which sales representatives?" can be handled in subquery form:
SELECT order_date, sales_rep FROM sales_order WHERE cust_id = ANY ( SELECT id FROM customer WHERE lname = ’Clarke’ OR fname = ’Suresh’)

Alternately, it can be phrased in join form
SELECT fname, lname, order_date, sales_rep FROM sales_order, customer WHERE cust_id=customer.id AND (lname = ’Clarke’ OR fname = ’Suresh’)

However, the request, "When did Ms. Clarke, Suresh, and any employee who is also a customer, place their orders?" would be phrased as a union query, and thus cannot be converted to a join:
SELECT order_date, sales_rep FROM sales_order WHERE cust_id = ANY ( SELECT id FROM customer WHERE lname = ’Clarke’ OR fname = ’Suresh’ UNION SELECT id FROM employee)

Similarly, the request "Find the order IDs and customer IDs of those orders that were not placed after all products of order #2001 were shipped," is naturally expressed with a subquery:

246

Chapter 8 Using Subqueries
SELECT id, cust_id FROM sales_order WHERE NOT order_date > ALL ( SELECT ship_date FROM sales_order_items WHERE id=2001)

It would be converted to the join:
SELECT sales_order.id, cust_id FROM sales_order, sales_order_items WHERE (sales_order_items.id=2001) and (order_date <= ship_date)

However, the request "Find the order IDs and customer IDs of those orders not shipped after the first shipping dates of all the products" would be phrased as the aggregate query:
SELECT id, cust_id FROM sales_order WHERE NOT order_date > ALL ( SELECT first (ship_date) FROM sales_order_items )

Therefore, it would not be converted to a join. Negating subqueries with the ANY and ALL operators The fifth criterion is a little more puzzling: queries of the form
SELECT select-list FROM table WHERE NOT expression comparison-operator ALL (subquery)

are converted to joins, as are queries of the form
SELECT select-list FROM table WHERE expression comparison-operator ANY (subquery)

but the queries
SELECT select-list FROM table WHERE expression comparison-operator ALL (subquery)

and
SELECT select-list FROM table WHERE NOT expression comparison-operator ANY (subquery)

are not. Logical equivalence of ANY and ALL expressions This is because the first two queries are in fact equivalent, as are the last two. Recall that the any operator is analogous to the OR operator, but with a variable number of arguments; and that the ALL operator is similarly analogous to the AND operator. Just as the expression 247

How subqueries work
NOT ((X > A) AND (X > B))

is equivalent to the expression
(X <= A) OR (X <= B)

the expression
NOT order_date > ALL ( SELECT first (ship_date) FROM sales_order_items )

is equivalent to the expression
order_date <= ANY ( SELECT first (ship_date) FROM sales_order_items )

Negating the ANY and ALL expressions

In general, the expression
NOT column-name operator ANY (subquery)

is equivalent to the expression
column-name inverse-operator ALL (subquery)

and the expression
NOT column-name operator ALL (subquery)

is equivalent to the expression
column-name inverse-operator ANY (subquery)

where inverse-operator is obtained by negating operator, as shown in the table: Table of operators and their inverses The following table lists the inverse of each operator.
Operator = < > =< => <> inverse-operator <> => =< > < =

248

Chapter 8 Using Subqueries

Set membership test
A query containing a subquery that follows the keyword IN is converted into a join only if: ♦ ♦ ♦ ♦ ♦ ♦ Example The main query does not contain a GROUP BY clause, and is not an aggregate query, or the subquery returns exactly one value. The subquery does not contain a GROUP BY clause. The subquery does not contain the keyword DISTINCT. The subquery is not a UNION query. The subquery is not an aggregate query. The conjunct ’expression IN (subquery)’ must not be negated.

So, the request "Find the names of the employees who are also department heads", expressed by the query:
SELECT emp_fname, emp_lname FROM employee WHERE emp_id IN ( SELECT dept_head_id FROM department
WHERE (dept_name=’Finance’ or dept_name = ’Shipping’))

would be converted to a joined query, as it satisfies the conditions. However, the request, "Find the names of the employees who are either department heads or customers" would not be converted to a join if it were expressed by the UNION query A UNION query following the IN operator can’t be converted
SELECT emp_fname, emp_lname FROM employee WHERE emp_id IN ( SELECT dept_head_id FROM department
WHERE (dept_name=’Finance’ or dept_name = ’Shipping’)

UNION SELECT cust_id FROM sales_order)

Similarly, the request "Find the names of employees who are not department heads" is formulated as the negated subquery
SELECT emp_fname, emp_lname FROM employee WHERE NOT emp_id IN ( SELECT dept_head_id FROM department
WHERE (dept_name=’Finance’ OR dept_name = ’Shipping’))

and would not be converted. 249

How subqueries work
The conditions that must be fulfilled for a subquery that follows the IN keyword and the ANY keyword to be converted to a join are identical. This is not a coincidence, and the reason for this is that the expression A query with an IN operator can be converted to one with an ANY operator
WHERE column-name IN (subquery)

is logically equivalent to the expression
WHERE column-name = ANY (subquery)

So the query
SELECT emp_fname, emp_lname FROM employee WHERE emp_id IN ( SELECT dept_head_id FROM department
WHERE (dept_name=’Finance’ or dept_name = ’Shipping’))

is equivalent to the query
SELECT emp_fname, emp_lname FROM employee WHERE emp_id = ANY ( SELECT dept_head_id FROM department
WHERE (dept_name=’Finance’ or dept_name = ’Shipping’))

Conceptually, Adaptive Server Anywhere converts a query with the IN operator to one with an ANY operator, and decides accordingly whether to convert the subquery to a join.

Existence test
A subquery that follows the keyword EXISTS is converted to a join only if it satisfies the following two conditions: ♦ ♦ ♦ Example The main query does not contain a GROUP BY clause, and is not an aggregate query, or the subquery returns exactly one value. The conjunct ’EXISTS (subquery)’ is not negated. The subquery is correlated; that is, it contains an outer reference.

Therefore, the request, "Which customers placed orders after July 13, 1994?", which can be formulated by this query whose non-negated subquery contains the outer reference customer.id = sales_order.cust_id, could be converted to a join.

250

Chapter 8 Using Subqueries
SELECT fname, lname FROM customer WHERE EXISTS ( SELECT * FROM sales_order WHERE (order_date > ’1994-07-13’) AND (customer.id = sales_order.cust_id))

The EXISTS keyword essentially tells the database server to check for empty result sets. When using inner joins, the database server automatically displays only the rows where there is data from all of the tables in the FROM clause. So, this query returns the same rows as does the one with the subquery:
SELECT fname, lname FROM customer, sales_order WHERE (sales_order.order_date > ’1994-07-13’) AND (customer.id = sales_order.cust_id).

251

How subqueries work

252

C H A P T E R

9

Adding, Changing, and Deleting Data

About this chapter

This chapter describes how to modify the data in a database. Most of the chapter is devoted to the INSERT, UPDATE, and DELETE statements, as well as statements for bulk loading and unloading.

Contents

Topic Data modification statements Adding data using INSERT Changing data using UPDATE Deleting data using DELETE

Page 254 255 259 261

253

Data modification statements

Data modification statements
The statements you use to add, change, or delete data are called data modification statements. The most common such statements include: ♦ ♦ ♦
Insert

adds new rows to a table

Update changes existing rows in a table Delete

removes specific rows from a table

Any single INSERT, UPDATE, or DELETE statement changes the data in only one table or view. In addition to the common statements, the LOAD TABLE and TRUNCATE TABLE statements are especially useful for bulk loading and deleting of data. Sometimes, the data modification statements are collectively known as the data modificaton language (DML) part of SQL.

Permissions for data modification
You can only execute data modification statements if you have the proper permissions on the database tables you want to modify. The database administrator and the owners of database objects use the GRANT and REVOKE statements to decide who has access to which data modification functions.

$ Permissions can be granted to individual users, groups, or the public
group. For more information on permissions, see "Managing User IDs and Permissions" on page 735.

Transactions and data modification
When you modify data, the transaction log stores a copy of the old and new state of each row affected by each data modification statement. This means that if you begin a transaction, realize you have made a mistake, and roll the transaction back, you also restore the database to its previous condition.

$ For more information about transactions, see "Using Transactions and
Isolation Levels" on page 381.

254

Chapter 9 Adding, Changing, and Deleting Data

Adding data using INSERT
You add rows to the database using the INSERT statement. The INSERT statement has two forms: you can use the VALUES keyword or a SELECT statement: INSERT using values The VALUES keyword specifies values for some or all of the columns in a new row. A simplified version of the syntax for the INSERT statement using the VALUES keyword is:
INSERT [ INTO ] table-name [ ( column-name, ... ) ] VALUES ( expression , ... )

You can omit the list of column names if you provide a value for each column in the table, in the order in which they appear when you execute a query using SELECT *. INSERT from SELECT You can use a SELECT statement in an INSERT statement to pull values from one or more tables. A simplified version of the syntax for the insert statement using a select statement is:
INSERT [ INTO ] table-name ( column-name, ... ) select-statement

Inserting values into all columns of a row
The following INSERT statement adds a new row to the department table, giving a value for every column in the row:
INSERT INTO department VALUES ( 702, ’Eastern Sales’, 902 )

Notes

Enter the values in the same order as the column names in the original CREATE TABLE statement, that is, first the ID number, then the name, then the department head ID. Surround the values by parentheses. Enclose all character data in single quotes. Use a separate insert statement for each row you add.

♦ ♦ ♦

255

Adding data using INSERT

Inserting values into specific columns
You can add data to some columns in a row by specifying only those columns and their values. Define all other columns not included in the column list must to allow NULL or have defaults. If you skip a column that has a default value, the default appears in that column. Adding data in only two columns, for example, dept_id and dept_name, requires a statement like this:
INSERT INTO department (dept_id, dept_name) VALUES ( 703, ’Western Sales’ )

The dept_head_id column has no default, but can allow NULL. A NULL is assigned to that column. The order in which you list the column names must match the order in which you list the values. The following example produces the same results as the previous one:
INSERT INTO department (dept_name, dept_id ) VALUES (’Western Sales’, 703)

Values for unspecified columns

When you specify values for only some of the columns in a row, one of four things can happen to the columns with no values specified: ♦ ♦ ♦
NULL entered

NULL appears if the column allows NULL and no default value exists for the column. The default value appears if a default exists

A default value entered

for the column.
A unique, sequential value entered A unique, sequential value appears if the column has the AUTOINCREMENT default or the IDENTITY property. INSERT rejected, and an error message appears An error message appears if the column does not allow NULL and no default exists.

By default, columns allow NULL unless you explicitly state NOT NULL in the column definition when creating tables. You can alter the default using the ALLOW_NULLS_BY_DEFAULT option. Restricting column data using constraints You can create constraints for a column or domain. Constraints govern the kind of data you can or cannot add.

$ For information on constraints, see "Using table and column
constraints" on page 367. You can explicitly insert NULL into a column by entering NULL. Do not enclose this in quotes, or it will be taken as a string.

Explicitly inserting NULL

256

Chapter 9 Adding, Changing, and Deleting Data
For example, the following statement explicitly inserts NULL into the dept_head_id column:
INSERT INTO department VALUES (703, ’Western Sales’, NULL )

Using defaults to supply values

You can define a column so that, even though the column receives no value, a default value automatically appears whenever a row is inserted. You do this by supplying a default for the column.

$ For information about defaults, see "Using column defaults" on
page 362.

Adding new rows with SELECT
To pull values into a table from one or more other tables, you can use a SELECT clause in the INSERT statement. The select clause can insert values into some or all of the columns in a row. Inserting values for only some columns can come in handy when you want to take some values from an existing table. Then, you can use update to add the values for the other columns. Before inserting values for some, but not all, columns in a table, make sure that either a default exists, or you specify NULL for the columns for which you are not inserting values. Otherwise, an error appears. When you insert rows from one table into another, the two tables must have compatible structures—that is, the matching columns must be either the same data types or data types between which Adaptive Server automatically converts. Example If the columns are in the same order in their create table statements, you do not need to specify column names in either table. Suppose you have a table named newproduct that contains some rows of product information in the same format as in the product table. To add to product all the rows in newproduct:
INSERT product SELECT * FROM newproduct

You can use expressions in a SELECT statement inside an INSERT statement. Inserting data into some columns You can use the SELECT statement to add data to some, but not all, columns in a row just as you do with the VALUES clause. Simply specify the columns to which you want to add data in the INSERT clause.

257

Adding data using INSERT

Inserting Data from the Same Table

You can insert data into a table based on other data in the same table. Essentially, this means copying all or part of a row. For example, you can insert new products, based on existing products, into the product table. The following statement adds new Extra Large Tee Shirts (of Tank Top, V-neck, and Crew Neck varieties) into the product table. The identification number is ten greater than the existing sized shirt:
INSERT INTO product SELECT id+ 10, name, description, ’Extra large’, color, 50, unit_price FROM product WHERE name = ’Tee Shirt’

Inserting documents and images
If you want to store documents or images in LONG BINARY columns in your database, you can write an application that reads the contents of the file into a variable, and supplies that variable as a value for an INSERT statement.

$ For information about adding INSERT statements to applications, see
"How to use prepared statements" on page 266. You can also use the xp_read_file system function to insert file contents into a table. This function is useful if you want to insert file contents from Interactive SQL, or some other environment that does not provide a full programming language. DBA authority is required to use this external function. Example In this example, you create a table, and insert an image into a column of the table. You can carry out these steps from Interactive SQL. 1 Create a table to hold some images.
CREATE TABLE pictures ( c1 INT DEFAULT AUTOINCREMENT PRIMARY KEY, filename VARCHAR(254), picture LONG BINARY )

2

Insert the contents of portrait.gif , in the current working directory of the database server, into the table.
INSERT INTO pictures (filename, picture) VALUES ( ’portrait.gif’, xp_read_file( ’portrait.gif’ ) )

$ For more information, see "xp_read_file system procedure" on
page 985 of the book ASA Reference. 258

Chapter 9 Adding, Changing, and Deleting Data

Changing data using UPDATE
You can use the UPDATE statement, followed by the name of the table or view, to change single rows, groups of rows, or all rows in a table. As in all data modification statements, you can change the data in only one table or view at a time. The UPDATE statement specifies the row or rows you want changed and the new data. The new data can be a constant or an expression that you specify or data pulled from other tables. If an UPDATE statement violates an integrity constraint, the update does not take place and an error message appears. For example, if one of the values being added is the wrong data type, or if it violates a constraint defined for one of the columns or data types involved, the update does not take place. UPDATE syntax A simplified version of the UPDATE syntax is:
UPDATE table-name SET column_name = expression WHERE search-condition

If the company Newton Ent. (in the customer table of the sample database) is taken over by Einstein, Inc., you can update the name of the company using a statement such as the following:
UPDATE customer SET company_name = ’Einstein, Inc.’ WHERE company_name = ’Newton Ent.’

You can use any expression in the WHERE clause. If you are not sure how the company name was entered, you could try updating any company called Newton, with a statement such as the following:
UPDATE customer SET company_name = ’Einstein, Inc.’ WHERE company_name LIKE ’Newton%’

The search condition need not refer to the column being updated. The company ID for Newton Entertainments is 109. As the ID value is the primary key for the table, you could be sure of updating the correct row using the following statement:
UPDATE customer SET company_name = ’Einstein, Inc.’ WHERE id = 109

The SET clause

The SET clause specifies the columns to be updated, and their new values. The WHERE clause determines the row or rows to be updated. If you do not have a WHERE clause, the specified columns of all rows are updated with the values given in the SET clause. 259

Changing data using UPDATE
You can provide any expression of the correct data type in the SET clause. The WHERE clause The WHERE clause specifies the rows to be updated. For example, the following statement replaces the One Size Fits All Tee Shirt with an Extra Large Tee Shirt
UPDATE product SET size = ’Extra Large’ WHERE name = ’Tee Shirt’ AND size = ’One Size Fits All’

The FROM clause

You can use a FROM clause to pull data from one or more tables into the table you are updating.

260

Chapter 9 Adding, Changing, and Deleting Data

Deleting data using DELETE
Simple DELETE statements have the following form:
DELETE [ FROM ] table-name WHERE column-name = expression

You can also use a more complex form, as follows
DELETE [ FROM ] table-name FROM table-list WHERE search-condition

The WHERE clause The FROM clause

Use the WHERE clause to specify which rows to remove. If no WHERE clause appears, the DELETE statement remove all rows in the table. The FROM clause in the second position of a DELETE statement is a special feature allowing you to select data from a table or tables and delete corresponding data from the first-named table. The rows you select in the FROM clause specify the conditions for the delete. This example uses the sample database. To execute the statements in the example, you should set the option WAIT_FOR_COMMIT to OFF. The following statement does this for the current connection only:
SET TEMPORARY OPTION WAIT_FOR_COMMIT = ’OFF’

Example

This allows you to delete rows even if they contain primary keys referenced by a foreign key, but does not permit a COMMIT unless the corresponding foreign key is deleted also. The following view displays products and the value of that product that has been sold:
CREATE VIEW ProductPopularity as SELECT product.id, SUM(product.unit_price * sales_order_items.quantity) as "Value Sold" FROM product JOIN sales_order_items ON product.id = sales_order_items.prod_id GROUP BY product.id

Using this view, you can delete those products which have sold less than $20,000 from the product table.
DELETE FROM product FROM product NATURAL JOIN ProductPopularity WHERE "Value Sold" < 20000

You should roll back your changes when you have completed the example:
ROLLBACK

261

Deleting data using DELETE

Deleting all rows from a table
You can use the TRUNCATE TABLE statement as a fast method of deleting all the rows in a table. It is faster than a DELETE statement with no conditions, because the delete logs each change, while the transaction log does not record truncate table operations individually. The table definition for a table emptied with the TRUNCATE TABLE statement remains in the database, along with its indexes and other associated objects, unless you enter a DROP TABLE statement. You cannot use TRUNCATE TABLE if another table has rows that reference it through a referential integrity constraint. Delete the rows from the foreign table, or truncate the foreign table and then truncate the primary table. TRUNCATE TABLE syntax The syntax of truncate table is:
TRUNCATE TABLE table-name

For example, to remove all the data in the sales_order table, type the following:
TRUNCATE TABLE sales_order

A TRUNCATE TABLE statement does not fire triggers defined on the table.

262

C H A P T E R

1 0

Using SQL in Applications

About this chapter

Previous chapters have described SQL statements as you execute them in Interactive SQL or in some other interactive utility. When you include SQL statements in an application there are other questions you need to ask. For example, how does your application handle query result sets? How can you make your application efficient? While many aspects of database application development depend on your application development tool, database interface, and programming language, there are some common problems and principles that affect multiple aspects of database application development. This chapter describes some principles common to most or all interfaces and provides a few pointers for more information. It does not provide a detailed guide for programming using any one interface.

Contents

Topic Executing SQL statements in applications Preparing statements Introduction to cursors Types of cursor Working with cursors Describing result sets Controlling transactions in applications

Page 264 266 269 272 275 281 283

263

Executing SQL statements in applications

Executing SQL statements in applications
The way you include SQL statements in your application depends on the application development tool and programming interface you use. ♦
ODBC

If you are writing directly to the ODBC programming interface, your SQL statements appear in function calls. For example, the following C function call executes a DELETE statement:
SQLExecDirect( stmt, "DELETE FROM employee WHERE emp_id = 105", SQL_NTS );

JDBC

If you are using the JDBC programming interface, you can execute SQL statements by invoking methods of the statement object. For example:
stmt.executeUpdate( "DELETE FROM employee WHERE emp_id = 105" );

Embedded SQL If you are using Embedded SQL, you prefix your C language SQL statements with the keyword EXEC SQL. The code is then run through a preprocessor before compiling. For example: EXEC SQL EXECUTE IMMEDIATE ’DELETE FROM employee WHERE emp_id = 105’;

Sybase Open Client

If you use the Sybase Open Client interface, your SQL statements appear in function calls. For example, the following pair of calls executes a DELETE statement:
ret = ct_command(cmd, CS_LANG_CMD, "DELETE FROM employee WHERE emp_id=105" CS_NULLTERM, CS_UNUSED); ret = ct_send(cmd);

Application Development Tools

Application development tools such as the members of the Sybase Enterprise Application Studio family provide their own SQL objects, which use either ODBC (PowerBuilder, Power++) or JDBC (Power J) under the covers.

$ For more
information

For detailed information on how to include SQL in your application, see your development tool documentation. If you are using ODBC or JDBC, consult the software development kit for those interfaces.

264

Chapter 10 Using SQL in Applications
For a detailed description of Embedded SQL programming, see "The Embedded SQL Interface" on page 7 of the book ASA Programming Interfaces Guide. Applications inside the server In many ways, stored procedures and triggers act as applications or parts of applications running inside the server. You can use many of the techniques here in stored procedures also. Stored procedures use statements very similar to Embedded SQL statements.

$ For information about stored procedures and triggres, see "Using
Procedures, Triggers, and Batches" on page 435. Java classes in the database can use the JDBC interface in the same way as Java applications outside the server. This chapter discusses some aspects of JDBC. For other information on using JDBC, see "Data Access Using JDBC" on page 591.

265

Preparing statements

Preparing statements
Each time a statement is sent to a database, the server must first prepare the statement. Preparing the statement can include: ♦ ♦ ♦ ♦ Reusing prepared statements can improve performance Parsing the statement and transforming it into an internal form. Verifying the correctness of all references to database objects by checking, for example, that columns named in a query actually exist. Causing the query optimizer to generate an access plan if the statement involves joins or subqueries,. Executing the statement after all these steps have been carried out.

If you find yourself using the same statement repeatedly, for example, inserting many rows into a table, repeatedly preparing the statement causes a significant and unnecessary overhead. To remove this overhead, some database programming interfaces provide ways of using prepared statements. Generally, using these methods requires the following steps: 1 2
Prepare the statement In this step you generally provide the statement with some placeholder character instead of the values. Repeatedly execute the prepared statement

In this step you supply values to be used each time the statement is executed. The statement does not have to be prepared each time.

3

Drop the statement

In this step you free the resources associated with the prepared statement. Some programming interfaces handle this step automatically.

Do not prepare statements that are used only once

In general, you should not prepare statements if you’ll only execute them once. There is a slight performance penalty for separate preparation and execution, and it introduces an unnecessary complexity into your application. In some interfaces, however, you do need to prepare a statement to associate it with a cursor. For information about cursors, see "Introduction to cursors" on page 269. The calls for preparing and executing statements are not a part of SQL, and they differ from interface to interface. Each of the Adaptive Server Anywhere programming interfaces provides a method for using prepared statements.

How to use prepared statements
This section provides a brief overview of how to use prepared statements. 266

Chapter 10 Using SQL in Applications
v To use a prepared statement:

1 2 3 4 5 6

Prepare the statement. Set up bound parameters, which will hold values in the statement. Assign values to the bound parameters in the statement. Execute the statement. Repeat steps 3 and 4 as needed. Drop the statement when finished. This step is not required in JDBC, as Java’s garbage collection mechanisms handle this for you.

The general procedure is the same, but the details vary from interface to interface. Comparing how to use prepared statements in different interfaces illustrates this point.
v To use a prepared statement in embedded SQL:

1 2 3 4

Prepare the statement using the EXEC SQL PREPARE command. Assign values to the parameters in the statement. Execute the statement using the EXE SQL EXECUTE command. Free the resources associated with the statement using the EXEC SQL DROP command.

The general procedure is the same, but the details vary from interface to interface. Comparing how to use prepared statements in different interfaces illustrates this point. Using prepared statements in ODBC
v To use a prepared statement in ODBC:

1 2 3 4

Prepare the statement using SQLPrepare. Bind the statement parameters using SQLBindParameter. Execute the statement using SQLExecute. Drop the statement using SQLFreeStmt.

$ For more information, see "Using prepared statements" on page 139 of
the book ASA Programming Interfaces Guide and the ODBC SDK documentation. To use a prepared statement with JDBC You can use prepared statements with JDBC both from a client application and inside the server.

267

Preparing statements
v To use a prepared statement in JDBC:

1 2 3

Prepare the statement using the prepareStatement method of the connection object. This returns a prepared statement object. Set the statement parameters using the appropriate setType methods of the prepared statement object. Here, Type is the data type assigned. Execute the statement using the appropriate method of the prepared statement object. For inserts, updates, and deletes this is the executeUpdate method.

$ For more information on using prepared statements in JDBC, see
"Using prepared statements for more efficient access" on page 609. To use a prepared statement with Sybase Open Client
v To use a prepared statement in Open Client:

1 2 3 4

Prepare the statement using the ct_dynamic function, with a CS_PREPARE type parameter. Set statement parameters using ct_param. Execute the statement using ct_dynamic with a CS_EXECUTE type parameter. Free the resources associated with the statement using ct_dynamic with a CS_DEALLOC type parameter.

$ For more information on using prepared statements in Open Client, see
"Using SQL in Open Client applications" on page 171 of the book ASA Programming Interfaces Guide.

268

Chapter 10 Using SQL in Applications

Introduction to cursors
When you execute a query in an application, the result set consists of a number of rows. In general, you do not know how many rows you are going to receive before you execute the query. Cursors provide a way of handling query result sets in applications. The way you use cursors, and the kinds of cursors available to you, depend on the programming interface you use. JDBC 1.0 provides rudimentary handling of result sets, while ODBC and Embedded SQL have many different kinds of cursors. Open Client cursors can only move forward through a result set.

$ For information on the kinds of cursors available through different
programming interfaces, see "Availability of cursors" on page 273.

What is a cursor?
A cursor is a symbolic name associated with a SELECT statement or stored procedure that returns a result set. It consists of a cursor result set (the set of rows resulting from the execution of a query associated with the cursor) and a cursor position (a pointer to one row within the cursor result set). A cursor is like a handle on the result set of a SELECT statement. It enables you to examine and possibly manipulate one row at a time. In Adaptive Server Anywhere, cursors support forward and backward movement through the query results.

269

Introduction to cursors
Absolute row from end Before first row -n - 1 -n -n + 1 -n +2

Absolute row from start 0 1 2 3

n- 2 n- 1 n n+ 1 After last row

-3 -2 -1 0

What you can do with cursors
With cursors, you can do the following: ♦ ♦ ♦ Loop over the results of a query. Carry out inserts, updates, and deletes at any point within a result set. Some programming interfaces allow you to use special features to tune the way result sets return to your application, providing substantial performance benefits for your application.

Steps in using a cursor
Using a cursor in Embedded SQL is different than using a cursor in other interfaces.
v To use a cursor in Embedded SQL:

1

Prepare a statement Cursors generally use a statement handle rather than a string. You need to prepare a statement to have a handle available. Declare the cursor Each cursor refers to a single SELECT or CALL statement. When you declare a cursor, you state the name of the cursor and the statement it refers to.

2

270

Chapter 10 Using SQL in Applications
3
Open the cursor

In the case of a CALL statement, opening the cursor executes the query up to the point where the first row is about to be obtained. Although simple fetch operations move the cursor to the next row in the result set, Adaptive Server Anywhere permits more complicated movement around the result set. How you declare the cursor determines which fetch operations are available to you. When you have finished with the cursor, close it.

4

Fetch results

5 6

Close the cursor Free the statement

To free the memory associated with the cursor and its associated statement you need to free the statement.

v To use a cursor in ODBC or Open Client:

1

Execute a statement

Execute a statement using the usual method for the interface. You can prepare and then execute the statement, or you can execute the statement directly. A cursor is implicitly opened when a statement that creates a result set is executed. When the cursor is opened, it is positioned before the first row of the result set.

2

Test to see if the statement returns a result set

3

Fetch results

Although simple fetch operations move the cursor to the next row in the result set, Adaptive Server Anywhere permits more complicated movement around the result set. When you have finished with the cursor, close it to free associated resources. If you used a prepared statement, free it to reclaim memory.

4 5 Prefetching rows

Close the cursor

Free the statement

In some cases, the interface library may carry out performance optimizations under the covers (such as prefetching results) so these steps in the client application may not correspond exactly to software operations.

271

Types of cursor

Types of cursor
You can choose from several kinds of cursors in Adaptive Server Anywhere when you declare the cursor. Cursors have the following properties: ♦
Unique or non-unique

Declaring a cursor to be unique forces the query to return all the columns required to uniquely identify each row. Often this means returning all the columns in the primary key. Any columns required but not specified are added to the result set. The default cursor type is non-unique. A cursor declared as read only may not be used in an UPDATE (positioned) or a DELETE (positioned) operation. The default cursor type us updatable.

Read only or updatable

Scrollability You can declare cursors to behave different ways as you move through the result set.

No Scroll Declaring a cursor NO SCROLL restricts fetching operations to fetching the next row or the same row again. You cannot rely on prefetches with no scroll cursors, so performance may be compromised. Dynamic scroll cursors With DYNAMIC SCROLL cursors you can carry out more flexible fetching operations. You can move backwards and forwards in the result set, or move to an absolute position. Scroll cursors Similar to DYNAMIC SCROLL cursors, SCROLL cursors behave differently when the rows in the cursor are modified or deleted after the first time the row is read. SCROLL cursors have more predictable behavior when other connections make changes to the database. Insensitive cursors

Also called STATIC cursors in ODBC, a cursor declared INSENSITIVE has its membership fixed when it is opened; and a temporary table is created with a copy of all the original rows. Fetching from an INSENSITIVE cursor does not see the effect of any other operation from a different cursor. It does see the effect of operations on the same cursor. Also, ROLLBACK or ROLLBACK TO SAVEPOINT do not affect INSENSITIVE cursors; these operations do not change the cursor contents. It is easier to write an application using INSENSITIVE cursors, since you only have to worry about changes you make explicitly to the cursor. You do not have to worry about actions taken by other users or by other parts of your application.

272

Chapter 10 Using SQL in Applications
INSENSITIVE cursors can be expensive if the cursor defines a large result set.

Availability of cursors
Not all interfaces provide support for all kinds of cursors. ♦ JDBC 1.1 does not use cursors, although the ResultSet object does have a next method that allows you to scroll through the results of a query in the client application. JDBC 2 does provide cursor operations. ODBC supports all kinds of cursors. ODBC provides a cursor type called a BLOCK cursor. When you use a BLOCK cursor, you can use SQLFetchScroll or SQLExtendedFetch to fetch a block of rows, rather than a single row. Block cursors behave identically to ESQL ARRAY fetches. ♦ ♦ Embedded SQL supports all the kinds of cursors. Sybase Open Client supports only NO SCROLL cursors. Also, a severe performance penalty results when using updateable, non-unique cursors.

Choosing a cursor type — dynamic vs scroll cursors
SCROLL cursors remember both rows and row positions within a cursor, so your application can be assured that these positions remain unchanged. If your program or another connection deletes one of these rows, it creates a "hole" in the cursor. If you fetch the row at this "hole" with a SCROLL cursor, you receive an error, indicating that there is no current row, and the cursor is left positioned on the "hole". In contrast, a DYNAMIC SCROLL cursor just skips the "hole" and retrieves the next row. DYNAMIC SCROLL cursors are more efficient than SCROLL cursors because they store less information. Therefore, use DYNAMIC SCROLL cursors unless you require the consistent behavior of SCROLL cursors. SCROLL cursors retain the result of previous fetch requests in a temporary table, so that if an application attempts to retrieve the same row more than once, it sees the original row image. This isolates the application from the affects of concurrent updates. For complex queries in a SCROLL cursor, the temporary table requirements can be significant, and this can impact performance. Queries that may produce slow SCROLL cursor performance include those with the following characteristics: ♦ Two or more conditions on the same column with an OR operator (such as X = 5 OR X = 4). 273

Types of cursor
♦ ♦ ♦ ♦ ♦ Example UNION ALL DISTINCT GROUP BY A subselect in the select list A subquery in the WHERE or HAVING clause

For example, an application could remember that Cobb is the second row in the cursor for the following query:
SELECT emp_lname FROM employee

If someone deletes the first employee (Whitney) while the SCROLL cursor is still open, a FETCH ABSOLUTE 2 still positions on Cobb while FETCH ABSOLUTE 1 returns an error. Similarly, if the cursor is on Cobb, FETCH PREVIOUS will return the Row Not Found error. In addition, a fetch on a SCROLL cursor returns the warning SQLE_ROW_UPDATED (104) if the row has changed since last reading. The warning only happens once. Subsequent fetches of the same row do not produce the warning. Similarly, an UPDATE (positioned) or DELETE (positioned) statement on a row modified since it was last fetched returns the SQLE_ROW_UPDATED_SINCE_READ error. An application must fetch the row again for the UPDATE or DELETE on a SCROLL cursor to work. An update to any column causes the warning/error, even if the column is not referenced by the cursor. For example, a cursor on a query returning emp_lname would report the update even if only the salary column were modified.
No warnings or errors in bulk operations mode

These update warning and error conditions do not occur in bulk operations mode (-b database server command-line switch).

274

Chapter 10 Using SQL in Applications

Working with cursors
This section describes how to carry out different kinds of operations using cursors.

Cursor positioning
A cursor can be positioned at one of three places: ♦ ♦ ♦ On a row Before the first row After the last row
Absolute row from end Before first row -n - 1 -n -n + 1 -n +2

Absolute row from start 0 1 2 3

n- 2 n- 1 n n+ 1 After last row

-3 -2 -1 0

When a cursor is opened, it appears before the first row. You can move the cursor position using the FETCH command (see "FETCH statement" on page 523 of the book ASA Reference) to an absolute position from the start or the end of the query results (using FETCH ABSOLUTE, FETCH FIRST, or FETCH LAST), or to a position relative to the current cursor position (using FETCH RELATIVE, FETCH PRIOR, or FETCH NEXT). The NEXT keyword is the default qualifier for the FETCH statement.

275

Working with cursors
The number of row positions you can fetch in a cursor is governed by the size of an integer. You can fetch rows numbered up to number 2147483646, which is one less than the value that can be held in an integer. When using negative numbers (rows from the end) you can fetch down to one more than the largest negative value that can be held in an integer. You can use special positioned versions of the UPDATE and DELETE statements to update or delete the row at the current position of the cursor. If the cursor is positioned before the first row or after the last row, a No current row of cursor error will be returned.
Cursor positioning problems

Inserts and some updates to DYNAMIC SCROLL cursors can cause problems with cursor positioning. The server will not put inserted rows at a predictable position within a cursor unless there is an ORDER BY clause on the SELECT statement. In some cases, the inserted row does not appear at all until the cursor is closed and opened again. With Adaptive Server Anywhere, this occurs if a temporary table had to be created to open the cursor (see "Temporary tables used in query processing" on page 824 for a description). The UPDATE statement may cause a row to move in the cursor. This happens if the cursor has an ORDER BY clause that uses an existing index (a temporary table is not created). Using STATIC SCROLL cursors alleviates these problems but requires more memory and processing.

Configuring cursors on opening
You can configure the following aspects of cursor behavior when you open the cursor: ♦
Isolation level

You can explicitly set the isolation level of operations on a cursor to be different from the current isolation level of the transaction. By default, cursors in Embedded SQL close at the end of a transaction. Opening a cursor with hold allows you to keep it open until the end of a connection, or until you explicitly close it. ODBC, JDBC and Open Client leave cursors open at the end of transactions by default.

Holding

276

Chapter 10 Using SQL in Applications

Fetching rows through a cursor
The simplest way of processing the result set of a query using a cursor is to loop through all the rows of the result set until there are no more rows. You can create a loop by: 1 2 3 Declaring and opening the cursor (Embedded SQL), or executing a statement that returns a result set (ODBC). Continue to fetch the next row until you get a Row Not Found indication. Closing the cursor.

How step 2 of this operation is carried out depends on the interface you use. For example: ♦ In ODBC SQLFetch, SQLExtendedFetch or SQLFetchScroll advances the cursor to the next row and returns the data.

$ For information on using cursors in ODBC, see "Working with
result sets" on page 141 of the book ASA Programming Interfaces Guide. ♦ In JDBC, the next method of the ResultSet object advances the cursor and returns the data.

$ For information on using the ResultSet object in JDBC, see
"Queries using JDBC" on page 607. ♦ In Embedded SQL, the FETCH statement carries out the same operation.

$ For information on using cursors in Embedded SQL, see "Cursors
in Embedded SQL" on page 33 of the book ASA Programming Interfaces Guide. ♦ In Open Client, ct_fetch advances the cursor to the next row and returns the data.

$ For information on using cursors in Open Client applications, see
"Using cursors" on page 172 of the book ASA Programming Interfaces Guide.

Fetching multiple rows
This section discusses how fetching multiple rows at a time can improve performance.

277

Working with cursors
Multiple-row fetching should not be confused with prefetching rows, which is described in the next section. Multiple row fetching is done by the application, while prefetching is transparent to the application, and provides a similar performance gain. Multiple-row fetches Some interfaces provide methods for fetching more than one row at a time into the next several fields in an array. Generally, the fewer separate fetch operations you execute, the fewer individual requests the server must respond to, and the better the performance. Multiple-row fetches are also sometimes called wide fetches. Cursors that use multiple-row fetches are sometimes called block cursors or fat cursors. ♦ In ODBC, you can set the number of rows that will be returned on each call to SQLFetchScroll or SQLExtendedFetch by setting the SQL_ROWSET_SIZE attribute. In Embedded SQL, the FETCH statement uses an ARRAY clause to control the number of rows fetched at a time. Open Client and JDBC do not support multi-row fetches. They do use prefetching.

Using multiple-row fetching

♦ ♦

Prefetching rows
Prefetches and multiple-row fetches are different. Prefetches can be carried out without explicit instructions from the client application. Prefetching retrieves rows from the server into a buffer on the client side, but does not make those rows available to the client application until the application fetches the appropriate row. By default, the Adaptive Server Anywhere client library prefetches multiple rows whenever an application fetches a single row. The Adaptive Server Anywhere client library stores the additional rows in a buffer. Prefetching assists performance by cutting down on client/server traffic, and increases throughput by making many rows available without a separate request to the server for each row or block of rows.

$ For information on controlling prefetches, see "PREFETCH option" on
page 206 of the book ASA Reference. Controlling prefetching from an application ♦ The PREFETCH option controls whether or not prefetching occurs. You can set the PREFETCH option to ON or OFF for a single connection. By default it is set to ON. In Embedded SQL, you can control prefetching on a per-cursor basis when you open a cursor, on an individual FETCH operation using the BLOCK clause.

278

Chapter 10 Using SQL in Applications
The application can specify a maximum number of rows contained in a single fetch from the server by specifying the BLOCK clause. For example, if you are fetching and displaying 5 rows at a time, you could use BLOCK 5. Specifying BLOCK 0 fetches 1 record at a time and also causes a FETCH RELATIVE 0 to always fetch the row from the server again. Although you can also turn off prefetch by setting a connection parameter on the application, it is more efficient to set BLOCK=0 than to set the PREFETCH option to OFF. For more information, see "PREFETCH option" on page 206 of the book ASA Reference ♦ In Open Client, you can control prefetching behavior using ct_cursor with CS_CURSOR_ROWS after the cursor is declared, but before it is opened.

Fetching with scrollable cursors
ODBC and Embedded SQL provide methods for using scrollable and DYNAMIC cursors. These methods allow you to move several rows forward at a time, or to move backwards through the result set. The JDBC or Open Client interfaces do not support scrollable cursors. Prefetching does not apply to scrollable operations. For example, fetching a row in the reverse direction does not prefetch several previous rows.

Modifying rows through a cursor
Cursors can do more than just read result sets from a query. You can also modify data in the database while processing a cursor. These operations are commonly called positioned update and delete operations, or put operations if the action is an insert. Not all query result sets allow positioned updates and deletes. If you carry out a query on a non-updateable view, then no changes occur to the underlying tables. Also, if the query involves a join, then you must specify which table you wish to delete from, or which columns you wish to update, when you carry out the operations. Insertions through a cursor can only be executed if any non-inserted columns in the table allow NULL or have defaults. ODBC, Embedded SQL, and Open Client permit data modification using cursors, but JDBC 1.1 does not. With Open Client, you can delete and update rows, but you can only insert rows on a single-table query. 279

Working with cursors

Which table are rows deleted from?

If you attempt a positioned delete on a cursor, the table from which rows are deleted is determined as follows: 1 2 If no FROM clause is included in the delete statement, the cursor must be on a single table only. If the cursor is for a joined query (including using a view containing a join), then the FROM clause must be used. Only the current row of the specified table is deleted. The other tables involved in the join are not affected. If a FROM clause is included, and no table owner is specified, the tablespec value is first matched against any correlation names.

3

$ For more information, see the "FROM clause" on page 532 of the
book ASA Reference. 4 5 6 If a correlation name exists, the table-spec value is identified with the correlation name. If a correlation name does not exist, the table-spec value must be unambiguously identifiable as a table name in the cursor. If a FROM clause is included, and a table owner is specified, the tablespec value must be unambiguously identifiable as a table name in the cursor. The positioned DELETE statement can be used on a cursor open on a view as long as the view is updateable.

7

Canceling cursor operations
You can cancel a request through an interface function. From Interactive SQL, you can cancel a request by pressing the Interrupt SQL Statement button on the toolbar (or by choosing Stop in the SQL menu). If you cancel a request that is carrying out a cursor operation, the position of the cursor is indeterminate. After canceling the request, you must locate the cursor by its absolute position, or close it.

Bookmarks and cursors
ODBC provides bookmarks, or values used to identify rows in a cursor. Adaptive Server Anywhere supports bookmarks for all kinds of cursors except DYNAMIC cursors.

280

Chapter 10 Using SQL in Applications

Describing result sets
Some applications build SQL statements which cannot be completely specified in the application. In some cases, for example, statements depend on a response from the user before the application knows exactly what information to retrieve, such as when a reporting application allows a user to select which columns to display. In such a case, the application needs a method for retrieving information about both the nature of the result set and the contents of the result set. The information about the nature of the result set, called a descriptor, identifies the data structure, including the number and type of columns expected to be returned. Once the application has determined the nature of the result set, retrieving the contents is straightforward. This result set metadata (information about the nature and content of the data) is manipulated using descriptors. Obtaining and managing the result set metadata is called describing. Since cursors generally produce result sets, descriptors and cursors are closely linked, although some interfaces hide the use of descriptors from the user. Typically, statements needing descriptors are either SELECT statements or stored procedures that return result sets. A sequence for using a descriptor with a cursor-based operation is as follows: 1 2 3 Allocate the descriptor. This may be done implicitly, although some interfaces allow explicit allocation as well. Prepare the statement. Describe the statement. If the statement is a stored procedure call or batch, and the result set is not defined by a result clause in the procedure definition, then the describe should occur after opening the cursor. Declare and open a cursor for the statement (Embedded SQL) or execute the statement. Get the descriptor and modify the allocated area if necessary. This is often done implicitly. Fetch and process the statement results. Deallocate the descriptor. Close the cursor. Drop the statement. Some interfaces do this automatically.

4 5 6 7 8 9

281

Describing result sets

Implementation notes

In Embedded SQL, a SQLDA (SQL Descriptor Area) structure holds the descriptor information.

$ For more information, see "The SQL descriptor area (SQLDA)" on
page 45 of the book ASA Programming Interfaces Guide. ♦ In ODBC, a descriptor handle allocated using SQLAllocHandle provides access to the fields of a descriptor. You can manipulate these fields using SQLSetDescRec, SQLSetDescField, SQLGetDescRec, and SQLGetDescField. Alternatively, you can use SQLDescribeCol and SQLColAttributes to obtain column information. ♦ In Open Client, you can use ct_dynamic to prepare a statement and ct_describe to describe the result set of the statement. However, you can also use ct_command to send a SQL statement without preparing it first, and use ct_results to handle the returned rows one by one. This is the more common way of operating in Open Client application development. In JDBC, the java.sql.ResultSetMetaData class provides information about result sets. You can also use descriptors for sending data to the engine (for example, with the INSERT statement), however, this is a different kind of descriptor than for result sets.

♦ ♦

$ For more information about input and output parameters of the
DESCRIBE statement, see the "DESCRIBE statement" on page 500 of the book ASA Reference.

282

Chapter 10 Using SQL in Applications

Controlling transactions in applications
Transactions are sets of atomic SQL statements. Either all statements in the transaction are executed, or none. This section describes a few aspects of transactions in applications.

$ For more information about transactions, see "Using Transactions and
Isolation Levels" on page 381.

Setting autocommit or manual commit mode
Some database programming interfaces have an autocommit mode (also called unchained mode). You control autocommit behavior in the database with the CHAINED database option, or in some database interfaces, by setting an autocommit interface option. If you wish to use transactions in your applications, you must use manual commit mode (also called chained mode). If you are using ODBC, you must turn autocommit mode off. In Adaptive Server Anywhere, CHAINED=ON by default (manual commit mode). You can set the current connection to operate in autocommit mode by setting the CHAINED database option to OFF. Using the CHAINED database option In autocommit mode, and if CHAINED=OFF, the database treats each statement as a transaction, and automatically commits each after execution. There is a distinct difference between the engine’s CHAINED mode and ODBC autocommit mode. For example, if CHAINED=OFF in a procedure call, each statement in the procedure is committed. However, if CHAINED=ON and ODBC autocommit=ON, the ODBC driver issues a commit after the entire procedure finishes executing. The performance and behavior of your application may change, depending on whether or not you are running in an autocommit mode. Autocommit is not recommended for most purposes. Setting autocommit mode ♦
ODBC By default, ODBC operates in autocommit mode. You can turn this mode off using the SQL_ATTR_AUTOCOMMIT connection attribute. ODBC autocommit and CHAINED options are independent of each other. JDBC

By default, JDBC operates in autocommit mode. You can turn this mode off using the setAutoCommit method of the connection object:
conn.setAutoCommit( false );

283

Controlling transactions in applications
JDBC autocommit and CHAINED options are independent of each other. ♦
Embedded SQL Embedded SQL uses the setting of the user’s CHAINED option to govern the transaction behavior. By default, this option is ON (manual commit). Open Client By default, a connection made through Open Client sets the CHAINED mode to OFF. You can change this behavior by setting the CHAINED database option to ON in your application (after connecting).

Controlling the isolation level
You can set the isolation level of a current connection using the ISOLATION_LEVEL database option. Some interfaces, such as ODBC, allow you to set the isolation level for a connection at connection time. You can reset this level later using the ISOLATION_LEVEL database option.

Cursors and transactions
In general, a cursor closes when a COMMIT is performed. There are two exceptions to this behavior: ♦ ♦ The CLOSE_ON_ENDTRANS database option is set to OFF. A cursor is opened WITH HOLD, which is the default with Open Client and JDBC.

If either of these two cases is true, the cursor remains open on a COMMIT. ROLLBACK and cursors If a transaction rolls back, then cursors close except for those cursors opened WITH HOLD. However, don’t rely on the contents of any cursor after a rollback. The draft ISO SQL3 standard states that on a rollback, all cursors (even those cursors opened WITH HOLD) should close. You can obtain this behavior by setting the ANSI_CLOSE_CURSORS_AT_ROLLBACK option to ON. Savepoints If a transaction rolls back to a savepoint, and if the ANSI_CLOSE_CURSORS_AT_ROLLBACK option is ON, then all cursors (even those cursors opened WITH HOLD) opened after the SAVEPOINT close.

284

Chapter 10 Using SQL in Applications

Cursors and isolation levels

You can change the isolation level of a connection during a transaction using the SET OPTION statement to alter the ISOLATION_LEVEL option. However, this change affects only closed cursors.

285

Controlling transactions in applications

286

C H A P T E R

1 1

International Languages and Character Sets

About this chapter Contents

This chapter describes how to configure your Adaptive Server Anywhere installation to handle international language issues.
Topic Introduction to international languages and character sets Understanding character sets in software Understanding locales Understanding collations Understanding character set translation Collation internals International language and character set tasks Page 288 291 297 303 311 314 319

287

Introduction to international languages and character sets

Introduction to international languages and character sets
This section provides an introduction to the issues you may face when working in an environment that uses more than one character set, or when using languages other than English. When you create a database, you specify a collating sequence or collation to be used by the database. A collation is a combination of a character set and a sort order for characters in the database.

Adaptive Server Anywhere international features
Adaptive Server Anywhere provides two sets of features that are of particular interest when setting up databases for languages. ♦
Collations You can choose from a wide selection of supplied collations when you create a database. By creating your database with the proper collation, you ensure proper sorting of data.

Whenever the database compares strings, sorts strings, or carries out other string operations such as case conversion, it does so using the collation sequence. The database carries out sorting and string comparison when statements such as the following are executed: ♦ ♦ ♦ ♦ Queries with an ORDER BY clause. Expressions that use string functions, such as LOCATE, SIMILAR, SOUNDEX. Conditions using the LIKE keyword. Queries that use index lookups on character data.

The database also uses collations to identify valid or unique identifiers (column names and so on). ♦
Character set translation

You can set up Adaptive Server Anywhere to convert data between the character set encoding on your server and client systems, thus maintaining the integrity of your data even in mixed character set environments. Character set translation is provided between client and server, and also by the ODBC driver. The Adaptive Server Anywhere ODBC driver provides OEM to ANSI character set translation and Unicode support.

288

Chapter 11 International Languages and Character Sets

Using the default collation
If you use the default actions when creating a database, the Database Creation utility infers a collation from the character set used by the operating system on the machine at which you create the database.

$ For information on how to find the default collation in your
environment, see "Finding the default collation" on page 319. If all the machines in your environment share the same character set, then this choice of collation ensures that all the character data in the database and in client applications is represented in the same manner. As long as the collation provides a proper character set and sort order for your data, using this default setting is a simple way of ensuring that characters are represented consistently throughout the system. If it is not possible to set up your system in this default manner, you need to decide which collation to use in your database, and whether to use character set translation to ensure that data is exchanged consistently between the pieces of your database system. This chapter provides the information you need to make and implement these decisions.

Character set questions and answers
The following table identifies where you can find answers to questions.
To answer the question... How do I set up my computing environment to treat character sets properly? How do I decide which collation to use for my database? How are characters represented in software, and Adaptive Server Anywhere in particular? What collations does Adaptive Server Anywhere provide? How do I ensure that error and informational messages sent from the database server to client applications are sent in the proper language and character set for my application? Consider reading... "Configuring your character set environment" on page 319 "Understanding collations" on page 303 "Understanding character sets in software" on page 291 "Supplied collations" on page 303 "Character translation for database messages" on page 311

289

Introduction to international languages and character sets
To answer the question... I have a different character set on client machines from that in use in the database. How can I get characters to be exchanged properly between client and server? What character sets can I use for connection strings? How do I create a collation that is different from the supplied ones? How do I change the collation sequence of an existing database? How do I create a database for Windows CE? Consider reading... "Starting a database server using character set translation" on page 323

"Connection strings and character sets" on page 312 "Creating a database with a custom collation" on page 326 "Changing a database from one collation to another" on page 327. "Creating databases for Windows CE" on page 305

290

Chapter 11 International Languages and Character Sets

Understanding character sets in software
This section provides general information about software issues related to international languages and character sets.

Pieces in the character set puzzle
There are several distinct aspects to character storage and display by computer software: ♦ ♦ Each piece of software works with a character set. A character set is a set of symbols, including letters, digits, spaces and other symbols. To handle these characters, each piece of software employs a character set encoding, in which each character is mapped onto one or more bytes of information, typically represented as hexadecimal numbers. This encoding is also called a code page. Database servers, which sort characters (for example, list names alphabetically), use a collation. A collation is a combination of a character encoding (a map between characters and hexadecimal numbers) and a sort order for the characters. There may be more than one sort order for each character set; for example, a case-sensitive order and a case-insensitive order, or two languages may sort characters in a different order. Characters are printed or displayed on a screen using a font, which is a mapping between characters in the character set and their appearance. Fonts are handled by the operating system. Operating systems also use a keyboard mapping to map keys or key combinations on the keyboard to characters in the character set.

Language issues in client/server computing
Database users working at client applications may see or access strings from the following sources: ♦
Data in the database

Strings and other text data are stored in the database. The database server processes these strings when responding to requests.

291

Understanding character sets in software
For example, the database server may be asked to supply all the last names beginning with a letter ordered less than N in a table. This request requires string comparisons to be carried out, and assumes a character set ordering. The database server receives strings from client applications as streams of bytes. It associates these bytes with characters according to the database character set. If the data is held in an indexed column, the index is sorted according to the sort order of the collation. ♦
Database server software messages

Applications can cause database errors to be generated. For example, an application may submit a query that references a column that does not exist. In this case, the database server returns a warning or error message. This message is held in a language resource library, which is a DLL or shared library called by Adaptive Server Anywhere. The client application interface displays text, and internally the client application may process text.

♦ ♦

Client application

Client software messages The client library uses the same language library as the database server to provide messages to the client application. Operating system The client operating system has text displayed on its interface, and may also process text.

For a satisfactory working environment, all these sources of text must work together. Loosely speaking, they must all be working in the user’s language and/or character set.

Code pages
Many languages have few enough characters to be represented in a singlebyte character set. In such a character set, each character is represented by a single byte: a two-digit hexadecimal number. At most, 256 characters can be represented in a single byte. No single-byte character set can hold all of the characters used internationally, including accented characters. This problem was addressed by the development of a set of code pages, each of which describes a set of characters appropriate for one or more national languages. For example, code page 869 contains the Greek character set, and code page 850 contains an international character set suitable for representing many characters in a variety of languages.

292

Chapter 11 International Languages and Character Sets

Upper and lower pages

With few exceptions, characters 0 to 127 are the same for all the single-byte code pages. The mapping for this range of characters is called the ASCII character set. It includes the English language alphabet in upper and lower case, as well as common punctuation symbols and the digits. This range is often called the seven-bit range (because only seven bits are needed to represent the numbers up to 127) or the lower page. The characters from 128 to 255 are called extended characters, or upper code-page characters, and vary from code page to code page. Problems with code page compatibility are rare if the only characters used are from the English alphabet, as these are represented in the ASCII portion of each code page (0 to 127). However, if other characters are used, as is generally the case in any non-English environment, there can be problems if the database and the application use different code pages.

Example

Suppose a database holding French language strings uses code page 850, and the client operating system uses code page 437. The character À (upper case A grave) is held in the database as character \xB7 (decimal value 183). In code page 437, character \xB7 is a graphical character. The client application receives this byte and the operating system displays it on the screen, the user sees a graphical character instead of an A grave.

ANSI and OEM code pages in Windows and Windows NT
For PC users, the issue is complicated because there are at least two code pages in use on most PCs. MS-DOS, as well as character-mode applications (those using the console or "DOS box") in Windows 95/98 and Windows NT, use code pages taken from the IBM set. These are called OEM code pages (Original Equipment Manufacturer) for historical reasons. Windows operating systems do not require the line drawing characters that were held in the extended characters of the OEM code pages, so they use a different set of code pages. These pages are based on the ANSI standard and are therefore commonly called ANSI code pages. Adaptive Server Anywhere supports collations based on both OEM and ANSI code pages. Example Consider the following situation: ♦ ♦ ♦ A PC is running the Windows 95 operating system with ANSI code page 1252. The code page for character-mode applications is OEM code page 437. Text is held in a database created using the collation corresponding to OEM code page 850.

293

Understanding character sets in software
An upper case A grave in the database is stored as character 183. This value is displayed as a graphical character in a character-mode application. The same character is displayed as a dot in a Windows application.

$ For information about choosing a single-byte collation for your
database, see "Understanding collations" on page 303.

Multibyte character sets
Some languages, such as Japanese and Chinese, have many more than 256 characters. These characters cannot all be represented using a single byte, but can be represented in multibyte character sets. In addition, some character sets use the much larger number of characters available in a multibyte representation to represent characters from many languages in a single, more comprehensive, character set. Multibyte character sets are of two types. Some are variable width, in which some characters are single-byte characters, others are double-byte, and so on. Other sets are fixed width, in which all characters in the set have the same number of bytes. Adaptive Server Anywhere supports only variable-width character sets. Example As an example, characters in the Shift-JIS character set are of either one or two bytes in length. If the value of the first byte is in the range of hexadecimal values from \x81 to \x9F or from \xE0 to \xEF (decimal values 129-159 or 224-239) the character is a two-byte character and the subsequent byte (called a follow byte) completes the character. If the first byte is outside this range, the character is a single-byte character and the next byte is the first byte of the following character. ♦ The properties of any Shift-JIS character can be read from its first byte also. Characters with a first byte in the range \x09 to \x0D, or \x20 are space characters. Characters in the ranges \x41 to \x5A, \x61 to \x7A, \x81 to \x9F or \xE0 to \xEF are considered to be alphabetic (letters). Characters in the range \x30 to \x39 are digits.

♦ ♦

$ For information on the multibyte character sets, see "Using multibyte
collations" on page 310.

Sorting characters using collations
The database collation sequence includes the notion of alphabetic ordering of letters, and extends it to include all characters in the character set, including digits and space characters. 294

Chapter 11 International Languages and Character Sets

Associating more than one character with each sort position

More than one character can be associated with each sort position. This is useful if you wish, for example, to treat an accented character the same as the character without an accent. Two characters with the same sort position are considered identical in all ways by the database. Therefore, if a collation assigned the characters a and e to the same sort position, then a query with the following search condition:
WHERE col1 = ’want’

is satisfied by a row for which col1 contains the entry went. At each sort position, lowercase and uppercase forms of a character can be indicated. For case-sensitive databases, the lowercase and uppercase characters are not treated as equivalent. For case-insensitive databases, the lowercase and uppercase versions of the character are considered equivalent.
Tip

Any code that selects a default collation for a German system should select 1252LATIN1, not 1252DEU. 1252DEU differentiates between characters with and without an umlaut, while 1252LATIN1 does not. 1252LATIN1 considers Muller and Müller equal, but 1252DEU does not consider them equal. Because 1252DEU views characters with umlauts as separate characters, it has the following alphabetic ordering: ob, öa.

First-byte collation orderings for multibyte character sets
A sorting order for characters in a multibyte character set can be specified only for the first byte. Characters that have the same first byte are sorted according to the hexadecimal value of the following bytes.

International aspects of case sensitivity
Adaptive Server Anywhere is always case preserving and case insensitive for identifiers, such as table names and column names. This means that the names are stored in the case in which they are created, but any access to the identifiers is done in a case-insensitive manner. For example, the names of the system tables are held in upper case (SYSDOMAIN, SYSTABLE, and so on), but access is case insensitive, so that the two following statements are equivalent:
SELECT * FROM systable SELECT *

295

Understanding character sets in software
FROM SYSTABLE

The equivalence of upper and lower case characters is enforced in the collation. There are some collations where particular care may be needed when assuming case insensitivity of identifiers. Example In the Turkish 857TRK collation, the lower case i does not have the character I as its upper case equivalent. Therefore, despite the case insensitivity of identifiers, the following two statements are not equivalent in this collation:
SELECT * FROM sysdomain SELECT * FROM SYSDOMAIN

296

Chapter 11 International Languages and Character Sets

Understanding locales
Both the database server and the client library recognize their language and character set environment using a locale definition.

Introduction to locales
The application locale, or client locale, is used by the client library when making requests to the database server, to determine the character set in which results should be returned. If character-set translation is enabled, the database server compares its own locale with the application locale to determine whether character set translation is needed. Different databases on a server may have different locale definitions.

$ For information on enabling character-set translation, see "Starting a
database server using character set translation" on page 323. The locale consists of the following components: ♦
Language The language is a two-character string using the ISO-639 standard values: DE for German, FR for French, and so on. Both the database server and the client have language values for their locale.

The database server uses the locale language to determine the following behavior: ♦ ♦ Which language library to load. The language is used together with the character set to determine which collation to use when creating databases, if no collation is explicitly specified.

The client library uses the locale language to determine the following behavior: ♦ ♦ Which language library to load. Which language to request from the database.

$ For more information, see "Understanding the locale language" on
page 298. ♦
Character set The character set is the code page in use. The client and server both have character set values, and they may differ. If they differ, character set translation may be required to enable interoperability.

For machines that use both OEM and ANSI code pages, the ANSI code page is the value used here.

297

Understanding locales

$ For more information, see "Understanding the locale character set"
on page 299. ♦
Collation label

The collation label is the Adaptive Server Anywhere collation. The client side does not use a collation label. Different databases on a database server may have different collation labels.

$ For more information, see "Understanding the locale collation
label" on page 302.

Understanding the locale language
The locale language is an indicator of the language being used by the user of the client application, or expected to be used by users of the database server.

$ For how to find locale settings, see "Determining locale information"
on page 320. The client library or database server determines the language component of the locale as follows: 1 It checks the SQLLOCALE environment variable, if it exists.

$ For more information, see "Setting the SQLLOCALE environment
variable" on page 302. 2 On Windows and Windows NT, it checks the Adaptive Server Anywhere language registry entry, as described in "Registry settings on installation" on page 11 of the book ASA Reference. On other operating systems, or if the registry setting is not present, it checks the operating system language setting.

3 Language label values

The following table shows the valid language label values, together with the equivalent ISO 639 labels:
Language label chinese danish french german italian japanese korean norwegian Alternative label simpchin N/A N/A N/A N/A N/A N/A norweg ISO_639 language code ZH DA FR DE IT JA KO NO

298

Chapter 11 International Languages and Character Sets
Language label polish portuguese russian spanish swedish tchinese ukrainian us_english Alternative label N/A portugue N/A N/A N/A tradchin N/A english ISO_639 language code PL PT RU ES SV TW UK EN

Understanding the locale character set
Both application and server locale definitions have a character set. The application uses its character set when requesting character strings from the server. If character set translation is enabled, the database server compares its character set with that of the application to determine whether character set translation is needed. The locale character set and language are used to determine which collation to use when creating a database if none is explicitly specified.

$ For how to find locale settings, see "Determining locale information"
on page 320. The client library or database server determines the character set as follows: 1 If the connection string specifies a character set, it is used.

$ For more information, see "CharSet connection parameter" on
page 50 of the book ASA Reference. 2 ODBC and Embedded SQL applications check the SQLLOCALE environment variable, if it exists.

$ For more information, see "Setting the SQLLOCALE environment
variable" on page 302. Open Client applications check the locales.dat file in the Sybase locales directory. 3 Character set information from the operating system is used to determine the locale: ♦ On Windows operating systems, use the GetACP system call. This returns the ANSI character set, not the OEM character set. 299

Understanding locales
♦ ♦ Character set labels On UNIX, default to ISO8859-1. On other platforms, use code page 850.

The following table shows the valid character set label values, together with the equivalent IANA labels and a description:
Character set label iso_1 cp850 cp437 roman8 mac sjis eucjis deckanji euccns eucgb cp932 iso88592 iso88595 iso88596 iso88597 iso88598 iso88599 iso15 mac_cyr mac_ee macgrk2 macturk greek8 turkish8 koi8 IANA label iso_8859-1:1987 <N/A> <N/A> hp-rpman8 macintosh shift_jis euc-jp <N/A> <N/A> <N/A> windows-31j iso_8859-2:1987 iso_8859-5:1988 iso_8859-6:1987 iso_8859-7:1987 iso_8859-8:1988 iso_8859-9:1989 <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> Description ISO 8859-1 Latin-1 IBM CP850 - European code set IBM CP437 - U.S. code set HP Roman-8 Standard Mac coding Shift JIS (no extensions) Sun EUC JIS encoding DEC Unix JIS encoding EUC CNS encoding: Traditional Chinese with extensions EUC GB encoding = Simplified Chinese Microsoft CP932 = Win31J-DBCS ISO 8859-2 Latin-2 Eastern Europe ISO 8859-5 Latin/Cyrillic ISO 8859-6 Latin/Arabic ISO 8859-7 Latin/Greek ISO 8859-8 Latin/Hebrew ISO 8859-9 Latin-5 Turkish ISO 8859-15 Latin1 with Euro, etc. Macintosh Cyrillic Macintosh Eastern European Macintosh Greek Macintosh Turkish HP Greek-8 HP Turkish-8 KOI-8 Cyrillic

300

Chapter 11 International Languages and Character Sets
Character set label tis620 big5 eucksc cp852 cp855 cp856 cp857 cp860 cp861 cp862 cp863 cp864 cp865 cp866 cp869 cp874 cp936 cp949 cp950 cp1250 cp1251 cp1252 cp1253 cp1254 cp1255 cp1256 cp1257 cp1258 utf8 IANA label <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> </N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> <N/A> utf-8 Description TIS-620 Thai standard Traditional Chinese (cf. CP950) EUC KSC Korean encoding (cf. CP949) PC Eastern Europe IBM PC Cyrillic Alternate Hebrew IBM PC Turkish PC Portuguese PC Icelandic PC Hebrew IBM PC Canadian French code page PC Arabic PC Nordic PC Russian IBM PC Greek Microsoft Thai SB code page Simplified Chinese Korean PC (MS) Traditional Chinese MS Windows 3.1 Eastern European MS Windows 3.1 Cyrillic MS Windows 3.1 US (ANSI) MS Windows 3.1 Greek MS Windows 3.1 Turkish MS Windows Hebrew MS Windows Arabic MS Windows Baltic MS Windows Vietnamese UTF-8 treated as a character set

301

Understanding locales

Understanding the locale collation label
Each database has its own collation. The collation label taken from the locale definition is used by the database server to determine which code page to use when initializing a database.

$ For how to find locale settings, see "Determining locale information"
on page 320. The database server determines the collation label as follows: 1 It checks the SQLLOCALE environment variable, if it exists.

$ For more information, see "Setting the SQLLOCALE environment
variable" on page 302. 2 Collation label values It uses an internal table to find a collation label corresponding to the language and character set.

The collation label is a label for one of the supplied Adaptive Server Anywhere collations, as listed in "Understanding collations" on page 303.

Setting the SQLLOCALE environment variable
The SQLLOCALE environment variable is a single string that consists of three semi-colon-separated assignments. It has the following form:
CS=cslabel;LANG=langlabel;LABEL=colabel

where cslabel, langlabel, and colabel are labels as defined in the previous sections.

$ For information on how to set environment variables, see "Setting
environment variables" on page 6 of the book ASA Reference.

302

Chapter 11 International Languages and Character Sets

Understanding collations
This section describes the supplied collations, and provides suggestions as to which collations to use under certain circumstances.

$ For information on how to create a database with a specific collation,
see "Creating a database with a named collation" on page 322. For information on changing a database from one collation to another, see "Changing a database from one collation to another" on page 327.

Supplied collations
The following collations are supplied with Adaptive Server Anywhere. You can obtain this list by entering the following command at a system command line:
dbinit -l Collation label 437LATIN1 437ESP 437SVE 819CYR 819DAN 819ELL 819ESP 819ISL 819LATIN1 819LATIN2 819NOR 819RUS 819SVE 819TRK 850CYR 850DAN 850ELL Type OEM OEM OEM ANSI ANSI ANSI ANSI ANSI ANSI ANSI ANSI ANSI ANSI ANSI OEM OEM OEM Description Code Page 437, Latin 1, Western Code Page 437, Spanish Code Page 437, Swedish/Finnish Code Page 819, Cyrillic Code Page 819, Danish Code Page 819, Greek Code Page 819, Spanish Code Page 819, Icelandic Code Page 819, Latin 1, Western Code Page 819, Latin 2, Central/Eastern European Code Page 819, Norwegian Code Page 819, Russian Code Page 819, Swedish/Finnish Code Page 819, Turkish Code Page 850, Cyrillic, Western Code Page 850, Danish Code Page 850, Greek

303

Understanding collations
Collation label 850ESP 850ISL 850LATIN1 850LATIN2 850NOR 850RUS 850SVE 850TRK 852LATIN2 852CYR 852POL 855CYR 856HEB 857TRK 860LATIN1 861ISL 862HEB 863LATIN1 865NOR 866RUS 869ELL 920TRK 932JPN 936ZHO 949KOR 950TWN 1250LATIN2 1250POL Type OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM OEM ANSI Multibyte Multibyte Multibyte Multibyte ANSI ANSI Description Code Page 850, Spanish Code Page 850, Icelandic Code Page 850, Latin 1 Code Page 850, Latin 2, Central/Eastern European Code Page 850, Norwegian Code Page 850, Russian Code Page 850, Swedish/Finnish Code Page 850, Turkish Code Page 852, Latin 2, Central/Eastern European Code Page 852, Cyrillic Code Page 852, Polish Code Page 855, Cyrillic Code Page 856, Hebrew Code Page 857, Turkish Code Page 860, Latin 1, Western Code Page 861, Icelandic Code Page 862, Hebrew Code Page 863, Latin 1, Western Code Page 865, Norwegian Code Page 866, Russian Code Page 869, Greek Code Page 920, Turkish, ISO-8859-9 Code Page 932, Japanese Shift-JIS encoding Code Page 936, Simplified Chinese, GB 2312-80 8-bit encoding Code Page 949, Korean KS C 5601-1987 encoding, Wansung Code Page 950, Traditional Chinese, Big 5 Encoding Code Page 1250, Windows Latin 2, Central/Eastern European Code Page 1250, Windows Latin 2, Polish

304

Chapter 11 International Languages and Character Sets
Collation label 1251CYR 1252DEU 1252LATIN1 1254TRK SJIS SJIS2 EUC_JAPAN EUC_CHINA EUC_TAIWAN EUC_KOREA ISO_1 ISO_BINENG ISO1LATIN1 ISO9LATIN1 WIN_LATIN1 WIN_LATIN5 UTF8 Type ANSI ANSI ANSI ANSI Multibyte Multibyte Multibyte Multibyte Multibyte Multibyte ANSI ANSI ANSI ANSI ANSI ANSI Multibyte Description Code Page 1251, Windows Cyrillic Code Page 1252, Windows Specialty German, Umlaut chars not equal Code Page 1252, Windows Latin 1, Western Code Page 1254, Windows Latin 1, Turkish, ISO 8859-9 with extensions Japanese Shift-JIS Encoding Japanese Shift-JIS Encoding, Sybase Adaptive Server Enterprise-compatible Japanese EUC JIS X 0208-1990 and JIS X 0212-1990 Encoding Simplified Chinese GB 2312-80 Encoding Taiwanese Big 5 Encoding Korean KS C 5601-1992 Encoding, Johad, Code Page 1361 ISO8859-1, Latin 1, Western Binary ordering, English ISO/ASCII 7-bit letter case mappings ISO8859-1, ISO Latin 1, Western, Latin 1 Ordering ISO8859-15, ISO Latin 9, Western, Latin 1 Ordering Code Page 1252 Windows Latin 1, Western, ISO8859-1 with extensions Code Page 1254 Windows Latin 5, Turkish, ISO8859-9 with extensions UCS-4 Transformation Format

Creating databases for Windows CE
Windows CE is a Unicode-based operating system. The Adaptive Server Anywhere ODBC driver supports either ASCII (8-bit) or Unicode strings, and carries out character set translation as needed. If developing Embedded SQL applications, you can use Windows API functions to get the Unicode versions of strings from the database.

305

Understanding collations
When creating databases for Windows CE, you should use a collation based on the same single- or multi-byte character set that Windows would use for the language of interest. For example, if you are using English, French, or German, use the 1252Latin1 collation. If you are using Japanese, use the SJIS2 collation, and if you are using Korean, use the 949KOR collation.

ANSI or OEM?
Adaptive Server Anywhere collations are based on code pages that are designated as either ANSI or OEM. In most cases, use of an ANSI code page is recommended. If you choose to use an ANSI code page, you must not use the ODBC translation driver in the ODBC data source configuration window. If you choose to use an OEM code page, you must do the following: ♦ ♦ Choose a code page that matches the OEM code pages on your users’ client machines. When setting up data sources for Windows-based ODBC applications, do choose the Adaptive Server Anywhere translation driver in the ODBC data source configuration. The translation driver converts between the OEM code page on your machine and the ANSI code page used by Windows. If the database collation is a different OEM code page than the one on your machine, an incorrect translation will be applied.

Notes on ANSI collations
The ISO_1 collation ISO_1 is provided for compatibility with the Adaptive Server Enterprise default ISO_1 collation. The differences are as follows: ♦ ♦ The lower case letter sharp s (\xDF) sorts with the lower case s in Adaptive Server Anywhere, but after ss in Adaptive Server Enterprise. The ligatures corresponding to AE and ae (\xC6 and \xE6) sort after A and a respectively in Adaptive Server Anywhere, but after AE and ae in Adaptive Server Enterprise.

The 1252LATIN1 collation

This collation is the same as WIN_LATIN1 (see below), but includes the euro currency symbol and several other characters (Z-with-caron and z-withcaron). For single-byte Windows operating systems, this is the recommended collation in most cases.

306

Chapter 11 International Languages and Character Sets
Windows NT service patch 4 changes the default character set in many locales to a new 1252 character set on which 1252 LATIN1 is based. If you have this service patch, you should use this collation instead of WIN_LATIN1. The euro symbol sorts with the other currency symbols. The WIN_LATIN1 collation WIN_LATIN1 is similar to ISO_1, except that Windows has defined characters in places where ISO_1 says "undefined", specifically the range \x80-\xBF. The differences from Adaptive Server Enterprise’s ISO_1 are as follows: ♦ The upper case and lower case Icelandic Eth (\xD0 and \xF0) is sorted with D in Adaptive Server Anywhere, but after all other letters in Adaptive Server Enterprise. The upper case and lower case Icelandic Thorn (\xD0 and \xF0) is sorted with T in Adaptive Server Anywhere, but after all other letters in Adaptive Server Enterprise. The upper-case Y-diaresis (\x9F) is sorted with Y in Adaptive Server Anywhere, and case converts with lowercase Y-diaresis (\xFF). In Adaptive Server Enterprise it is undefined and sorts after \x9E. The lower case letter sharp s (\xDF) sorts with the lower case s in Adaptive Server Anywhere, but after ss in Adaptive Server Enterprise. Ligatures are two characters combined into a single character. The ligatures corresponding to AE and ae (\xC6 and \xE6) sort after A and a respectively in Adaptive Server Anywhere, but after AE and ae in Adaptive Server Enterprise. The ligatures corresponding to OE and oe (\x8C and \x9C) sort with O in Adaptive Server Anywhere, but after OE and oe in Adaptive Server Enterprise. The upper case and lower case letter S with caron (\x8A and \x9A) sorts with S in Adaptive Server Anywhere, but is undefined in Adaptive Server Enterprise, sorting after \x89 and \x99.

♦ ♦

The ISO1LATIN1 collation

This collation is the same as ISO_1, but with sorting for values in the range A0-BF. For compatibility with Adaptive Server Enterprise, the ISO_1 collation has no characters for 0xA0-0xBF. However the ISO Latin 1 character set on which it is based does have characters in these positions. The ISO1LATIN1 collation reflects the characters in these positions. If you are not concerned with Adaptive Server Enterprise compatibility, ISOLATIN1 is generally recommended instead of ISO_1.

The ISO9LATIN1 collation

This collation is the same as ISO1LATIN1, but it includes the euro currency symbol and the other new characters included in the 1252 LATIN1 collation. 307

Understanding collations
If your machine uses the ISO Latin 9 character set, then you should use this collation.

Notes on OEM collations
The following table shows the built-in collations that correspond to OEM code pages. The table and the corresponding collations were derived from several manuals from IBM concerning National Language Support, subject to the restrictions mentioned above. (This table represents the best information available at the time of writing.)
Country Language Primary Code Page 850 437 850 850 850 855 850 855 850 437 852 852 850 850 850 850 869 852 850 850 Primary Collation 850ESP 437LATIN1 850LATIN1 850LATIN1 850LATIN1 855CYR 850LATIN1 855CYR 850LATIN1 437LATIN1 852LATIN2 852LATIN2 850DAN 850SVE 850LATIN1 850LATIN1 869ELL 852LATIN2 850ISL 850LATIN1 437 437 437 850 850 861 437 437SVE 437LATIN1 437LATIN1 850ELL 850LATIN2 861ISL 437LATIN1 437 850 863 850 850 850 437LATIN1 850CYR 863LATIN1 850LATIN1 850LATIN2 850LATIN2 Secondary Code Page 437 850 437 437 437 Secondary Collation 437ESP 850LATIN1 437LATIN1 437LATIN1 437LATIN1

Argentina Australia Austria Belgium Belgium Belarus Brazil Bulgaria Canada Canada Croatia Czech Republic Denmark Finland France Germany Greece Hungary Iceland Ireland

Spanish English German Belgian Dutch Belgian French Belarussian Portuguese Bulgarian Cdn French English Croatian Czech Danish Finnish French German Greek Hungarian Icelandic English

308

Chapter 11 International Languages and Character Sets
Country Language Primary Code Page 862 850 850 850 437 865 850 852 850 852 866 437 437 852 852 850 850 850 850 850 857 850 437 850 852 855 852 Primary Collation 862HEB 850LATIN1 850ESP 850LATIN1 437LATIN1 865NOR 850ESP 852LATIN2 850LATIN1 852LATIN2 866RUS 437LATIN1 437LATIN1 852LATIN2 852LATIN2 850ESP 850SVE 850LATIN1 850LATIN1 850LATIN1 857TRK 850LATIN1 437LATIN1 850ESP 852LATIN2 855CYR 852LATIN2 Secondary Code Page 856 437 437 437 850 850 437 850 860 850 850 850 850 850 850 437 437 437 437 437 850 437 850 437 850 852 850 Secondary Collation 856HEB 437LATIN1 437ESP 437LATIN1 850LATIN1 850NOR 437ESP 850LATIN2 860LATIN1 850LATIN2 850RUS 850LATIN1 850LATIN1 850LATIN2 850LATIN2 437ESP 437SVE 437LATIN1 437LATIN1 437LATIN1 850TRK 437LATIN1 850LATIN1 437ESP 850LATIN2 852CYR 850LATIN2

Israel Italy Mexico Netherlands New Zealand Norway Peru Poland Portugal Romania Russia S. Africa S. Africa Slovak Republic Slovenia Spain Sweden Switzerland Switzerland Switzerland Turkey UK USA Venezuela Yugoslavia Yugoslavia Yugoslavia

Hebrew Italian Spanish Dutch English Norwegian Spanish Polish Portuguese Romanian Russian Afrikaans English Slovakian Slovenian Spanish Swedish French German Italian Turkish English English Spanish Macedonian Serbian Cyrillic Serbian Latin

309

Understanding collations

Using multibyte collations
This section describes how multibyte character sets are handled. The description applies to the supported collations and to any multibyte custom collations you may create. Adaptive Server Anywhere provides collations using several multibyte character sets.

$ For a complete listing, see "Understanding collations" on page 303.
Adaptive Server Anywhere supports variable width character sets. In these sets, some characters are represented by one byte, and some by more than one, to a maximum of four bytes. The value of the first byte in any character indicates the number of bytes used for that character, and also indicates whether the character is a space character, a digit, or an alphabetic (alpha) character. Adaptive Server Anywhere does not support fixed-length multibyte character sets such as 2-byte Unicode (UCS-2) or 4-byte Unicode (UCS-4).

310

Chapter 11 International Languages and Character Sets

Understanding character set translation
Adaptive Server Anywhere can carry out character set translation among character sets that represent the same characters, but at different positions in the character set or code page. There needs to be a degree of compatibility between the character sets for this to be possible. For example, character set translation is possible between EUC-JIS and Shift-JIS character sets, but not between EUC-JIS and OEM code page 850. This section describes how Adaptive Server Anywhere carries out character set translation. This information is provided for advanced users, such as those who may be deploying applications or databases in a multi-characterset environment.

Character translation for database messages
Error and other messages from the database software are held in a language resource library. Localized versions of this library are provided with localized versions of Adaptive Server Anywhere. Client application users may see messages from the database as well as data from the database. Some database messages, which are strings from the language library, may include placeholders that are filled by characters from the database. For example, if you execute a query with a column that does not exist, the returned error messages is:
Column column-name not found

where column-name is filled in from the database. To present these kinds of information to the client application in a consistent manner, even if the database is in a different character set from the language library, the database server automatically translates the characters of the messages so that they match the character set used in the database collation.
v To use character translation for database messages:

Ensure that the collation for your database is compatible with the character set used on your computer, and with the character set used in the Adaptive Server Anywhere language resource library. The language resource library differs among different localized versions of Adaptive Server Anywhere. You must check that the characters of interest to you exist in each character set.

311

Understanding character set translation
Messages are always translated into the database collation character set, regardless of whether the -ct command-line option is used.

Translate to client character set

Translate to EUC-JIS

Shift-JIS Language library EUC-JIS

A further character set translation is carried out if the database server -ct command-line option is used, and if the client character set is different from that used in the database collation.

Connection strings and character sets
Connection strings present a special case for character set translation. The connection string is parsed by the client library, in order to locate or start a database server. This parsing is done with no knowledge of the server character set or language. The interface library parses the connection string as follows: 1 It is broken down into its keyword = value components. This can be done independently of the character set, as long as you do not use the curly braces {} around CommLinks parameters. Instead, use the recommended parentheses (). Curly braces are valid follow bytes (bytes other than the first byte) in some multi-byte character sets. The server is located. The server name is interpreted according to the character set of the client machine. In the case of Windows operating systems, the ANSI character set is used. Extended chars can be used unless they cause character set conversion issues between the client and server machines. For maximum compatibility among different machines, you should use server names built from ASCII characters 0 to 127 (33 to 126, excluding control characters and space) , using no punctuation characters. Server names are truncated at 40 characters.

2

312

Chapter 11 International Languages and Character Sets
3 4 The DatabaseName or DatabaseFile parameter is interpreted in the database server character set. Once the database is located, the remaining connection parameters are interpreted according to its character set.

Avoiding character-set translation
There is a performance cost associated with character set translation. If you can set up an environment such that no character set translation is required, then you do not have to pay this cost, and your setup is simpler to maintain. If you work with a single-byte character set and are concerned only with seven-bit ASCII characters (values 0 through 127), then you do not need character set translation. Even if the code pages are different in the database and on the client operating system, they are compatible over this range of characters. Many English-language installations will meet these requirements. If you do require use of extended characters, there are other steps you may be able to take: ♦ If the code page on your client machine operating system matches that used in the database, no character set translation is needed for data in the database. For example, in many environments it is appropriate to use the 1252LATIN1 collation in your database, which corresponds to the Windows NT code page in many single-byte environments. ♦ If you are able to use a version of Adaptive Server Anywhere built for your language, and if you use the code page on your operating system, no character set translation is needed for database messages. The character set used in the Adaptive Server Anywhere message strings is as follows:
Language English French German Japanese Character set cp1252 cp1252 cp1252L cp932 (Shift-JIS)

Also, recall that client/server character set translation takes place only if the database server is started using the -ct command-line switch.

313

Collation internals

Collation internals
This section describes internal technical details of collations, including the file format of collation files.

$ This section is of particular use if you want to create a database using a custom collation. For information on the steps involved, see "Creating a custom collation" on page 325, and "Creating a database with a custom collation" on page 326.
You can create a database using a collation different from the supplied collations. This section describes how to build databases using such a custom collation. In building multibyte custom collations, you can specify which ranges of values for the first byte signify single- and double-byte (or more) characters, and which specify space, alpha, and digit characters. However, all first bytes of value less than \x40 must be single-byte characters, and no follow bytes may have values less than \x40. This restriction is satisfied by all supported encodings. Collation files may include the following elements: ♦ ♦ ♦ ♦ ♦ Comment lines, which are ignored by the database. A title line. A collation sequence section. An Encodings section. A Properties section.

Comment lines
In the collation file, spaces are generally ignored. Comment lines start with either the percent sign (%) or two dashes (--).

The title line
The first non-comment line must be of the form:
Collation label (name)

In this statement:

314

Chapter 11 International Languages and Character Sets

Descriptions of arguments

Argument Collation label

Description A required keyword. The collation label, which appears in the system tables as SYS.SYSCOLLATION.collation_label and SYS.SYSINFO.default_collation. The label must contain no more than 10 characters. A descriptive term, used for documentation purposes. The name should contain no more than 128 characters.

name

For example, the Shift-JIS collation file contains the following collation line, with label SJIS and name (Japanese Shift-JIS Encoding):
Collation SJIS (Japanese Shift-JIS Encoding)

The collation sequence section
After the title line, each non-comment line describes one position in the collation. The ordering of the lines determines the sort ordering used by the database, and determines the result of comparisons. Characters on lines appearing higher in the file (closer to the beginning) sort before characters that appear later. The form of each line in the sequence is:
[sort-position] : character [ [, character ] ...]

or
[sort-position] : character [lowercase uppercase]

Descriptions of arguments

Argument sort-position

Description Optional. Specifies the position at which the characters on that line will sort. Smaller numbers represent a lesser value, so will sort closer to the beginning of the sorted set. Typically, the sort-position is omitted, and the characters sort immediately following the characters from the previous sort position. The character whose sort-position is being specified. Optional. Specifies the lowercase equivalent of the character. If not specified, the character has no lowercase equivalent. Optional. Specifies the uppercase equivalent of the character. If not specified, the character has no uppercase equivalent.

character lowercase uppercase

315

Collation internals
Multiple characters may appear on one line, separated by commas ,. In this case, these characters are sorted and compared as if they were the same character. Specifying character and sortposition Each character and sort position is specified in one of the following ways:
Specification \dnnn \xhh ’c’ c Description Decimal number, using digits 0-9 (such as \d001) Hexadecimal number, using digits 0-9 and letters a-f or A-F (such as \xB4) Any character in place of c (such as ’,’) Any character other than quote (’), back-slash (\), colon (:) or comma (,). These characters must use one of the previous forms.

The following are some sample lines for a collation:
% : : : : : : : : : : % : : : : % % : : Sort some special characters at the beginning: ’ ’ _ \xF2 \xEE \xF0 ’,’ ; ’:’ ! Sort some letters in alphabetical order A a A a a A B b B b b B Sort some E’s from code page 850, including some accented extended characters: e e E, \x82 \x82 \x90, \x8A \x8A \xD4 E e E, \x90 \x82 \x90, \xD4 \x8A \xD4

Other syntax notes

For databases using case-insensitive sorting and comparison (no -c specified on the dbinit command line), the lower case and upper case mappings are used to find the lower case and upper case characters that will be sorted together. For multibyte character sets, the first byte of a character is listed in the collation sequence, and all characters with the same first byte are sorted together, and ordered according to the value of the following bytes. For example, the following is part of the Shift-JIS collation file:
: \xfb

316

Chapter 11 International Languages and Character Sets
: : \xfc \xfd

In this collation, all characters with first byte \xfc come after all characters with first byte \xfb and before all characters with first byte \xfd. The twobyte character \xfc \x01 would be ordered before the two-byte character \xfc \x02. Any characters omitted from the collation are added to the end of the collation. The tool that processes the collation file issues a warning.

The Encodings section
The Encodings section is optional, and follows the collation sequence. It is not useful for single-byte character sets. The Encodings section lists which characters are lead-bytes, for multi-byte character sets, and what are valid follow-bytes. For example, the Shift-JIS Encodings section is as follows:
Encodings: [\x00-\x80,\xa0-\xdf,\xf0-\xff] [\x81-\x9f,\xe0-\xef][\x00-\xff]

The first line following the section title lists valid single-byte characters. The square brackets enclose a comma-separated list of ranges. Each range is listed as a hyphen-separated pair of values. In the Shift-JIS collation, values \x00 to \x80 are valid single-byte characters, but \x81 is not a valid singlebyte character. The second line following the section title lists valid multibyte characters. Any combination of one byte from the second line followed by one byte from the first is a valid character. Therefore \x81\x00 is a valid double-byte character, but \xd0 \x00 is not.

The Properties section
The Properties section is optional, and follows the Encodings section. If a Properties section is supplied, an Encodings section must be supplied also. The Properties section lists values for the first-byte of each character that represent alphabetic characters, digits, or spaces. The Shift-JIS Properties section is as follows:
Properties: space: [\x09-\x0d,\x20]

317

Collation internals
digit: [\x30-\x39] alpha: [\x41-\x5a,\x61-\x7a,\x81-\x9f,\xe0-\xef]

This indicates that characters with first bytes \x09 to \x0d, as well as \x20, are to be treated as space characters, digits are found in the range \x30 to \x39 inclusive, and alphabetic characters in the four ranges \x41-\x5a, \x61\x7a, \x81-\x9f, and \xe0-\xef.

318

Chapter 11 International Languages and Character Sets

International language and character set tasks
This section groups together the tasks associated with international language and character set issues.

Finding the default collation
If you do not explicitly specify a collation when creating a database, a default collation is used. The default collation depends on the operating system you are working on.
v To find the default collation for your machine:

1 2

Start Interactive SQL. Connect to the sample database. Enter the following command:
SELECT PROPERTY( ’DefaultCollation’ )

The default collation is returned. For more information about this collation, see "Supplied collations" on page 303.

Configuring your character set environment
This section describes how to set up your computing environment so that character set issues are handled properly. If you set your locale environments properly, then you do not need to explicitly choose collations for your databases, and you do not need to turn on character set translation between client and server.
v To configure your character set environment:

1

Determine the default locale of each computing platform in your environment. The default locale is the character set and language of each computer. On Windows operating systems, the character set is the ANSI code page.

$ For how to find locale information, see "Determining locale
information" on page 320. 2 Decide whether the locale settings are appropriate for your environment.

$ For more information, see "Understanding collations" on page 303.

319

International language and character set tasks
3 If the default settings are inappropriate, decide on a character set, language, and database collation that matches your data and avoids character set translation.

$ For more information, see "Avoiding character-set translation" on
page 313. 4 Set locales on each of the machines in the environment to these values.

$ For more information, see "Setting locales" on page 321.
5 Create your database using the default collation. If the default collation does not match your needs, create a database using a named collation.

$ For more information, see "Creating a database with a named
collation" on page 322, and "Changing a database from one collation to another" on page 327. When choosing the collation for your database, ♦ Choose a collation that uses a character set and sort order appropriate for the data in the database. It is often the case that there are several alternative collations that meet this requirement, including some that are OEM collations and some that are ANSI collations. There is a performance cost, as well as extra complexity in system configuration, when you use character set translation. Choose a collation that avoids the need for character set translation. You can avoid character set translation by using a collation sequence in the database that matches the character set in use on your client machine operating system. In the case of Windows operating systems on the client machine, choose the ANSI character set.

$ For information, see "Avoiding character-set translation" on
page 313.

Determining locale information
You can determine locale information using system functions.

$ For a complete list, see "System functions" on page 310 of the book
ASA Reference.
v To determine the locale of a database server:

1 2

Start Interactive SQL, and connect to a database server. Execute the following statement to determine the database server character set:

320

Chapter 11 International Languages and Character Sets
SELECT PROPERTY( ’CharSet’ )

The query returns one of the supported character sets listed in "Character set labels" on page 300. 3 Execute the following statement to determine the database server language:
SELECT PROPERTY( ’Language’ )

The query returns one of the supported languages listed in "Language label values" on page 298. 4 Execute the following statement to determine the database server default collation:
SELECT PROPERTY( ’DefaultCollation’ )

The query returns one of the collations listed in "Supplied collations" on page 303. Notes To obtain client locale information, connect to a database server running on your current machine. To obtain the character set for an individual database, execute the following statement:
SELECT DB_PROPERTY ( ’CharSet’ )

Setting locales
You can use the default locale on your operating system, or explicitly set a locale for use by the Adaptive Server Anywhere components on your machine.
v To set the Adaptive Server Anywhere locale on a computer:

1

If the default locale is appropriate for your needs, you do not need to take any action.

$ To find out the default locale of your operating system, see "Determining locale information" on page 320.
2 If you need to change the locale, create a SQLLOCALE environment variable with the following value:
Charset=cslabel;Language=langlabel;CollationLabel=co label

321

International language and character set tasks
where cslabel is a character set label from the list in "Character set labels" on page 300, langlabel is a language label from the list in "Language label values" on page 298, and CollationLabel is taken from the list in "Understanding collations" on page 303, or is a custom collation label.

$ For information on how to set environment variables on different
operating systems, see "Setting environment variables" on page 6 of the book ASA Reference.

Creating a database with a named collation
You may specify the collation for each database when you create the database. The default collation is inferred from the code page and sort order of the database server’s computer’s operating system.
v To specify a database collation when creating a database (Sybase Central):

You can use the Create Database wizard in Sybase Central to create a database. The wizard has a Collation Sequence page where you choose a collation from a list.

v To specify a database collation when creating a database (Command line):

1

List the supplied collation sequences:
dbinit -l

322

Chapter 11 International Languages and Character Sets
The first column of the list is the collation label, which you supply when creating the database.
437LATIN1 437ESP 437SVE 819CYR 819DAN 819ELL ... Code Code Code Code Code Code Page Page Page Page Page Page 437, 437, 437, 819, 819, 819, Latin 1, Western Spanish Swedish/Finnish Cyrillic Danish Greek

2

Create a database using the dbinit utility, specifying a collation sequence using the -z option. The following command creates a database with a Greek collation.
dbinit -z 869ELL mydb.db

v To specify a database collation when creating a database (SQL)

You can use the CREATE DATABASE statement to create a database. The following statement creates a database with a Greek collation:
CREATE DATABASE ’mydb.db’ COLLATION ’819ELL’

Starting a database server using character set translation
Character set translation takes place if the client and server locales are different, but only if you specifically turn on character set conversion on the database server command line.
v To enable character-set translation on a database server:

Start the database server using the -ct command-line option. For example:
dbsrv7 -ct asademo.db

Using ODBC code page translation
Adaptive Server Anywhere provides an ODBC translation driver. This driver converts characters between OEM and ANSI code pages. It allows Windows applications using ANSI code pages to be compatible with databases that use OEM code pages in their collations.

323

International language and character set tasks

Not needed if you use ANSI character sets

If you use an ANSI character set in your database, and are using ANSI character set applications, you do not need to use this translation driver. The translation driver carries out a mapping between the OEM code page in use in the "DOS box" and the ANSI code page used in the Windows operating system. If your database uses the same code page as the OEM code page, the characters are translated properly. If your database does not use the same code page as your machine’s OEM code page, you will still have compatibility problems. Embedded SQL does not provide any such code page translation mechanism.
v To use the ODBC translation driver:

1

In the ODBC Administrator, choose Add to create a new Adaptive Server Anywhere data source or Configure to edit an existing Adaptive Server Anywhere data source. On the ODBC tab of the ODBC Configuration for Adaptive Server Anywhere window, click Select and choose Adaptive Server Anywhere 7.0 Translator from the list of translation drivers.

2

Using character set translation for Sybase Central and Interactive SQL
Interactive SQL and Sybase Central both employ internal OEM to ANSI code page translation if the database uses an OEM character set. As with the ODBC translation driver, there is an assumption that the OEM code page on the local machine matches the data in the database.
v To turn off character set translation in Interactive SQL:

Set the Interactive SQL option CHAR_OEM_Translation to a value of OFF.
SET OPTION CHAR_OEM_TRANSLATION = ’OFF’

$ For more information on OEM to ANSI character set translation in
Interactive SQL, see "CHAR_OEM_TRANSLATION option" on page 176 of the book ASA Reference.

324

Chapter 11 International Languages and Character Sets

Creating a custom collation
If none of the supplied collations meet your needs, you can modify a supplied collation to create a custom collation. You can then use this custom collation when creating a database.

$ For a list of supplied collations, see "Supplied collations" on page 303.
v To create a custom collation:

1

Decide on a starting collation

You should choose a collation as close as possible to the one you want to create as a starting point for your custom collation. For a listing of supplied collations, see "Understanding collations" on page 303. Alternatively, run dbinit with the -l (lower case L) option:
dbinit -l

2

Create a custom collation file

You do this using the Collation utility.

The output is a collation file. For example, the following statement extracts the 1252LATIN1 collation into a file named mycol.col:
dbcollat -z 1252LATIN1 mycol.col

3 4

Edit the custom collation file

Open the collation file (in this case

mycol.col) in a text editor.
Change the name of the collation

The name of the collation is specified on a line near the top of the file, starting with Collation. You should edit this line to provide a new name. The name you need to change is the second word on the line not counting switches: in the example above, it is 1252LATIN1.

The other entries on this line relate the Adaptive Server Anywhere collation label to the names that Java and the Sybase TDS interface give to the same collation information. If you are not using these interfaces you do not need to alter these entries. The Collation line takes the following form:
Collation ASA_NAME asa_description charset so_sensitive so_insensitive jdk

where character set label (charset) and the two sort-order labels (so_sensitive and so_insensitive) are state which Open Client character set and sort order is the closest to the current collation. The jdk label is the closest character set known to Java. 5
Change the collation definition

Make the changes you wish in the custom collation file to define your new collation. 325

International language and character set tasks

$ For information on the collation file contents and format, see
"Collation internals" on page 314. 6
Convert the file to SQL scripts You do this using the dbcollat command-line utility using the -d switch.

For example, the following command line creates the mycustmap.sql file and mycustom.sql files from the mycol.col collation file:
dbcollat -d mycol.col mycustmap.sql mycustom.sql

7

Add the SQL scripts to the scripts in your installation The scripts used when creating databases are held in the scripts subdirectory of your Adaptive Server Anywhere installation directory. Append the contents of mycustmap.sql to custmap.sql, and the contents of mycustom.sql to end of custom.sql.

The new collation is now in place, and can be used when creating a database.

Creating a database with a custom collation
If none of the supplied collations meet your needs, you can create a database using a custom collation. The custom collation is used in indexes and any string comparisons.
v To create a database with a custom collation:

1

Create a custom collation. You must have a custom collation in place to use when creating a database.

$ For instructions on how to create custom collations, see "Creating
a custom collation" on page 325. 2 Create the new database. Use the Initialization utility, specifying the name of your custom collation. For example, the following command line creates a database named
newcol.db using the custom collation sequence newcol.
dbinit -z newcol temp.db

You can also use the Initialization utility from Sybase Central.

326

Chapter 11 International Languages and Character Sets

Changing a database from one collation to another
Changing your database from one collation to another may be a good idea for any number of reasons. It can be especially useful, for example, if you want to: ♦ ♦ avoid the need for character set translation across your setup unify the character set you are using with the collation in your database. Using the same character set defined in your database is especially important for sorting purposes. switch from one character set to another. You may, for example, want to move from a DOS character set to a Windows character set.

Simply modifying the collation in an existing database is not permitted, since it would invalidate all the indexes for that database. In order to change the collation for a database, you must rebuild the database. Rebuilding a database creates a new database with new settings (including collation settings), using the old database’s data. When you change the collation for a database, there are two main scenarios to consider. The difference between the two lies in whether the character set of the data needs to be changed. Example 1 In the first example, only the collation needs to be changed. The data should not change character sets. To resolve the collation issue, you need to rebuild the database with new collation settings using the old data. Consider an old database using the 850LATIN1 collation. If the database contains data inserted from a Windows ’windowed’ application, it is likely that the data is actually from the CP1252 character set, which does not match CP850 used by the 850LATIN1 collation. This situation will often be discovered when an ORDER BY clause seems to sort accented characters incorrectly. To correct this problem, you would create a new database using the 1252LATIN1 collation, and move the data from the old database to the new database without translation, since the data is already in the character set (CP1252) that matches the new database’s collation. The simplest way to ensure that translation does not occur is to start the server without the -ct switch.

$ For more information about rebuilding a database, see "Rebuilding a
database" on page 697.

$ For more information about specifying collations when creating
databases, see "Creating a database with a named collation" on page 322.

327

International language and character set tasks

Example 2

In the second situation, both the collation and the character set need to be changed. To resolve the collation and character set issues, you need to rebuild the database with the new collation settings, and change the character set of the data. Suppose that the 850LATIN1 database had been used properly such that it contains characters from the CP850 character set. However, you want to update both the collation and the character set, perhaps to avoid extra translation. You would create a new database using 1252LATIN1, and move the data from the old database to the new database with translation, thus converting the CP850 characters to CP1252. The translation of the database data from one character set to another occurs using the client-server translation feature of the server. This feature, invoked using the -ct command line switch, translates the data during the communication between the client application and the server. The database’s collation determines the server’s character set. The locale setting of the operating system determines the client’s default character set, however, the client's character set can be overridden by the CHARSET parameter of the SQLLOCALE environment variable. Since character set translation takes place during the communication between the client application and the server, an external unload or reload is necessary. If you use internal unload and reload, you will avoid character set translation altogether, and end up where you began. Similarly, if character set translation occurs in both the unload and the reload steps, you will perform the translation and then immediately undo the translation and still end up where you began. Character set translation can occur in either the unload or the reload steps, but not in both.
v To convert a database from one collation to another, and translate the data’s character set (using translation on reload):

1

Unload the data from the source database. You can use the Unload utility to produce a reload.sql file and a set of data files in the character set of the source database. Since we do not want any translation during this phase, ensure that the 6.0 server running the source database does not use the -ct switch. If the unload/reload is occurring on a single machine, use the -ix switch to do an internal unload and an external reload. If the unload/reload occurs across machines, use the Unload utility with the -xx switch to force an external unload and an external reload.

328

Chapter 11 International Languages and Character Sets
Remember that an “external” unload or reload means that an application (dbunload and DBISQL) opens a cursor on the database and either reads or writes the data to disk. An “internal” unload or reload means that an UNLOAD TABLE or LOAD TABLE is used so that the server reads or writes the data itself. If you want to unload specific tables, use the Interactive SQL OUTPUT statement.

$ For more information on the Unload utility, see "The Unload
utility" on page 138 of the book ASA Reference. 2 Create a target database with the appropriate collation using the Initialization utility and the -z switch. To reload the new database, you must be using at least version 6.0.1. The database should be created using the version of the server and tools corresponding to the server that they will use to run it.

$ For more information on specifying collations when creating
databases, see "Creating a database with a named collation" on page 322. 3 Start the target database using the 6.0 engine/server running with the ct and -z switch. The -ct switch enables the database server to carry out character set translation into the character set of the target database. The -ct switch is required. The –z switch, while not required, allows for verification of the character sets that will be used, and that translation will occur.

$ For more information, see "Starting a database server using
character set translation" on page 323. 4 Create the SQLLOCALE environment variable with the CHARSET parameter set to the character set of the source database on the client The value of the CHARSET parameter is based on the character set of the data, not on the old collation.

$ For more information, see "Setting the SQLLOCALE environment
variable" on page 302. 5 Start Interactive SQL and connect to the server started in step 3. Ensure that the engine message window shows that the client is using the SQLLOCALE character set. There should be a message similar to : server character translation is on, database charset is “iso-1”, client charset is “cp1252”

329

International language and character set tasks
6 From Interactive SQL, use the Read command to run the reload.sql script, or use the INPUT statement to load the data files created in step 1. The data transferred to the target database will be translated to the character set appropriate to the collation defined when the database was created in step 2. 7 Once the conversion is complete, shutdown the engine and Interactive SQL and unset the SQLLOCALE environment variable. If you no longer require character set translation, remove the -ct switch from the engine command line for subsequent runs.

330

P A R T

T H R E E

Relational Database Concepts

This part describes key concepts and strategies for effective use of Adaptive Server Anywhere.

331

332

C H A P T E R

1 2

Designing Your Database

About this chapter

This chapter introduces the basic concepts of relational database design and gives you step-by-step suggestions for designing your own databases. It uses the expedient technique known as conceptual data modeling, which focuses on entities and the relationships between them.
Topic Introduction Database design concepts The design process Designing the database table properties Page 334 335 341 355

Contents

333

Introduction

Introduction
While designing a database is not a difficult task for small and medium sized databases, it is an important one. Bad database design can lead to an inefficient and possibly unreliable database system. Because client applications are built to work on specific parts of a database, and rely on the database design, a bad design can be difficult to revise at a later date.

$ This chapter covers database design in an elementary manner. For more advanced information, you may wish to the DataArchitect documentation. DataArchitect is a component of Sybase PowerDesigner, a database design tool. $ You may also wish to consult an introductory book such as A Database
Primer by C. J. Date. If you are interested in pursuing database theory, C. J. Date’s An Introduction to Database Systems is an excellent textbook on the subject. Java classes and database design The addition of Java classes to the available data types extends the relational database concepts on which this chapter is based. Database design involving Java classes is not discussed in this chapter.

$ For information on designing databases that take advantage of Java
class data types, see "Java database design" on page 583.

334

Chapter 12 Designing Your Database

Database design concepts
In designing a database, you plan what things you want to store information about, and what information you will keep about each one. You also determine how these things are related. In the common language of database design, what you are creating during this step is a conceptual database model. Entities and relationships The distinguishable objects or things that you want to store information about are called entities. The associations between them are called relationships. You might like to think of the entities as nouns in the language of database description and the relationships as verbs. Conceptual models are useful because they make a clean distinction between the entities and relationships. These models hide the details involved in implementing a design in any particular database management system. They allow you to focus on fundamental database structure. Hence, they also form a common language for the discussion of database design. Entity-relationship diagrams The main component of a conceptual database model is a diagram that shows the entities and relationships. This diagram is commonly called an entityrelationship diagram. In consequence, many people use the name entityrelationship modeling to refer to the task of creating a conceptual database model. Conceptual database design is a top-down design method. There are now sophisticated tools such as Sybase PowerDesigner that help you pursue this method, or other approaches. This chapter is an introductory chapter only, but it does contain enough information for the design of straightforward databases.

Entities
An entity is the database equivalent of a noun. Distinguishable objects such as employees, order items, departments and products are all examples of entities. In a database, a table represents each entity. The entities that you build into your database arise from the activities for which you will be using the database, whether that be tracking sales calls, maintaining employee information, or some other activity. Attributes and identifiers Each entity contains a number of attributes. Attributes are particular characteristics of the things that you would like to store. For example, in an employee entity, you might want to store an employee ID number, first and last names, an address, and other particular information that pertains to a particular employee. Attributes are also known as properties. 335

Database design concepts
You depict an entity using a rectangular box. Inside, you list the attributes associated with than entity.
Employee Employee Number First Name Last Name Address

An identifier is one or more attributes on which all the other attributes depend. It uniquely identifies an item in the entity. Underline the names of attributes that you wish to form part of an identifier. In the Employee entity, above, the Employee Number uniquely identifies an employee. All the other attributes store information that pertains only to that one employee. For example, an employee number uniquely determines an employee’s name and address. Two employees might have the same name or the same address, but you can make sure that they don’t have the same employee number. Employee Number is underlined to show that it is an identifier. It is good practice to create an identifier for each entity. As will be explained later, these identifiers become primary keys within your tables. Primary key values must be unique and cannot be null or undefined. They identify each row in a table uniquely and improve the performance of the database server.

Relationships
A relationship between entities is the database equivalent of a verb. An employee is a member of a department, or an office is located in a city. Relationships in a database may appear as foreign key relationships between tables, or may appear as separate tables themselves. You will see examples of each in this chapter. The relationships in the database are an encoding of rules or practices that govern the data in the entities. If each department has one department head, you can create a one-to-one relationship between departments and employees to identify the department head. Once a relationship is built into the structure of the database, there is no provision for exceptions. There is nowhere to put a second department head. Duplicating the department entry would involve duplicating the department ID, which is the identifier. Duplicate identifiers are not allowed.

336

Chapter 12 Designing Your Database

Tip

Strict database structure can benefit you, because it can eliminate inconsistencies, such as a department with two managers. On the other hand, you as the designer should make your design flexible enough to allow some expansion for unforeseen uses. Extending a well-designed database is usually not too difficult, but modifying the existing table structure can render an entire database and its client applications obsolete. Cardinality of relationships There are three kinds of relationships between tables. These correspond to the cardinality (number) of the entities involved in the relationship. ♦
One-to-one relationships You depict a relationship by drawing a line

between two entities. The line may have other markings on it such as the two little circles shown. Later sections explain the purpose of these marks.
Department Management Relationship Employee

One employee manages one department. ♦
One-to-many relationships The fact that one item contained in Entity 1 can be associated with multiple entities in Entity 2 is denoted by the multiple lines forming the attachment to Entity 2.
Office Phone Location Relationship Telephones

One office can have many telephones. ♦
Many-to-many relationships

In this case, draw multiple lines for the
Warehouses

connections to both entities.
Parts Storage Relationship

One warehouse can hold many different parts and one type of part can be stored at many warehouses. Roles You can describe each relationship with two roles. Roles are verbs or phrases that describe the relationship from each point of view. For example, a relationship between employees and departments might be described by the following two roles. 1 An employee is a member of a department. 337

Database design concepts
2 A department contains an employee.
Employee Employee Number First Name Last Name Address is a member of Department Department ID Department Name

contains

Roles are very important because they afford you a convenient and effective means of verifying your work.
Tip

Whether reading from left-to-right or from right-to-left, the following rule makes it easy to read these diagrams: Read the 1 name of the first entity, 2 role next to the first entity, 3 cardinality from the connection to the second entity, and 4 name of the second entity. Mandatory elements The little circles just before the end of the line that denotes the relation serve an important purpose. A circle means that an element can exist in the one entity without a corresponding element in the other entity. If a cross bar appears in place of the circle, that entity must contain at least one element for each element in the other entity. An example will clarify these statements.
Publisher ID Number Publisher Name

publishes Books ID Number Title writes is written by Authors ID Number First Name Last Name

is published by

This diagram corresponds to the following four statements. 1 2 3 4 A publisher publishes zero or more books. A book is published by exactly one publisher. A book is written by one or more authors. An author writes zero or more books.

338

Chapter 12 Designing Your Database

Tip

Think of the little circle as the digit 0 and the cross bar as the number one. The circle means at least zero. The cross bar means at least one. Reflexive relationships Sometimes, a relationship will exist between entries in a single entity. In this case, the relationship is called reflexive. Both ends of the relationship attach to a single entity.
Employee Employee Number First Name Last Name Address manages reports to

This diagram corresponds to the following two statements. 1 2 An employee reports to at most one other employee. An employee manages zero or more or more employees.

Notice that in the case of this relation, it is essential that the relation be optional in both directions. Some employees are not managers. Similarly, at least one employee should head the organization and hence report to no one.

$ Naturally, you would also like to specify that an employee cannot be his
or her own manager. This restriction is a type of business rule. Business rules are discussed later as part of "The design process" on page 341.

Changing many-to-many relationships into entities
When you have attributes associated with a relationship, rather than an entity, you can change the relationship into an entity. This situation sometimes arises with many-to-many relationships, when you have attributes that are particular to the relationship and so you cannot reasonably add them to either entity. Suppose that your parts inventory is located at a number of different warehouses. You have drawn the following diagram.
Parts Part Number Description stored at Warehouse contains Warehouse ID Address

339

Database design concepts
But you wish to record the quantity of each part stored at each location. This attribute can only be associated with the relationship. Each quantity depends on both the parts and the warehouse involved. To represent this situation, you can redraw the diagram as follows:
Parts Part Number Description stored at Inventory Quantity contains Warehouse Warehouse ID Address

Notice the following details of the transformation: 1 Two new relations join the relation entity with each of the two original entities. They inherit their names from the two roles of the original relationship: stored at and contains, respectively. Each entry in the Inventory entity demands one mandatory entry in the Parts entity and one mandatory entry in the Warehouse entity. These relationships are mandatory because a storage relationship only makes sense if it is associated with one particular part and one particular warehouse. The new entity is dependent on both the Parts entity and on the Warehouse entity, meaning that the new entity is identified by the identifiers of both of these entities. In this new diagram, one identifier from the Parts entity and one identifier from the Warehouse entity uniquely identify an entry in the Inventory entity. The triangles that appear between the circles and the multiple lines that join the two new relationships to the new Inventory entity denote the dependencies.

2

3

Do not add either a Part Number or Warehouse ID attribute to the Inventory entity. Each entry in the Inventory entity does depend on both a particular part and a particular warehouse, but the triangles denote this dependence more clearly.

340

Chapter 12 Designing Your Database

The design process
There are five major steps in the design process. ♦ ♦ ♦ ♦ ♦ "Step 1: Identify entities and relationships" on page 341. "Step 2: Identify the required data" on page 344. "Step 3: Normalize the data" on page 346. "Step 4: Resolve the relationships" on page 349. "Step 5: Verify the design" on page 352.

$ For information about implementing the database design, see "Working
with Database Objects" on page 111.

Step 1: Identify entities and relationships
v To identify the entities in your design and their relationship to each other:

1

Define high-level activities Identify the general activities for which you will use this database. For example, you may want to keep track of information about employees. Identify entities

2

For the list of activities, identify the subject areas you need to maintain information about. These subjects will become entities. For example, hire employees, assign to a department, and determine a skill level. Look at the activities and determine what the relationships will be between the entities. For example, there is a relationship between parts and warehouses. Define two roles to describe each relationship.

3

Identify relationships

4

Break down the activities You started out with high-level activities. Now, examine these activities more carefully to see if some of them can be broken down into lower-level activities. For example, a high-level activity such as maintain employee information can be broken down into:

♦ ♦ ♦

Add new employees. Change existing employee information. Delete terminated employees.

341

The design process
5
Identify business rules Look at your business description and see what rules you follow. For example, one business rule might be that a department has one and only one department head. These rules will be built into the structure of the database.

Entity and relationship example
Example ACME Corporation is a small company with offices in five locations. Currently, 75 employees work for ACME. The company is preparing for rapid growth and has identified nine departments, each with its own department head. To help in its search for new employees, the personnel department has identified 68 skills that it believes the company will need in its future employee base. When an employee is hired, the employee’s level of expertise for each skill is identified. Define high-level activities Some of the high-level activities for ACME Corporation are: ♦ ♦ ♦ ♦ ♦ ♦ ♦ Identify the entities and relationships Hire employees. Terminate employees. Maintain personal employee information. Maintain information on skills required for the company. Maintain information on which employees have which skills. Maintain information on departments. Maintain information on offices.

Identify the entities (subjects) and the relationships (roles) that connect them. Create a diagram based on the description and high-level activities. Use boxes to show entities and lines to show relationships. Use the two roles to label each relationship. You should also identify those relationships that are one-to-many, one-to-one, and many-to-many using the appropriate annotation. Below, is a rough entity-relationship diagram. It will be refined throughout the chapter.

342

Chapter 12 Designing Your Database
Skill is acquired by Department is headed by is capable of manages contains Employee works out of contains Office manages reports to is a member of

Break down the high-level activities

The following lower-level activities below are based on the high-level activities listed above: ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ Add or delete an employee. Add or delete an office. List employees for a department. Add a skill to the skill list. Identify the skills of an employee. Identify an employee’s skill level for each skill. Identify all employees that have the same skill level for a particular skill. Change an employee’s skill level.

These lower-level activities can be used to identify if any new tables or relationships are needed. Identify business rules Business rules often identify one-to-many, one-to-one, and many-to-many relationships. The kind of business rules that may be relevant include the following: ♦ ♦ ♦ ♦ ♦ There are now five offices; expansion plans allow for a maximum of ten. Employees can change department or office. Each department has one department head. Each office has a maximum of three telephone numbers. Each telephone number has one or more extensions.

343

The design process
♦ ♦ ♦ When an employee is hired, the level of expertise in each of several skills is identified. Each employee can have from three to twenty skills. An employee may or may not be assigned to an office.

Step 2: Identify the required data
v To identify the required data:

1 2 3 4 5 6 Identify supporting data

Identify supporting data. List all the data you need to track. Set up data for each entity. List the available data for each entity. The data that describes an entity (subject) answers the questions who, what, where, when, and why. List any data required for each relationship (verb). List the data, if any, that applies to each relationship.

The supporting data you identify will become the names of the attributes of the entity. For example, the data below might apply to the Employee entity, the Skill entity, and the Expert In relationship.
Employee Employee ID Employee first name Employee last name Employee department Employee office Employee address Skill Skill ID Skill name Description of skill Expert In Skill level Date skill was acquired

If you make a diagram of this data, it will look something like this picture:
Employee Employee ID First name Last name Home address is acquired by is capable of Skill Skill ID Skill name Skill description

344

Chapter 12 Designing Your Database
Observe that not all of the attributes you listed appear in this diagram. The missing items fall into two categories: 1 Some are contained implicitly in other relationships; for example, Employee department and Employee office are denoted by the relations to the Department and Office entities, respectively. Others are not present because they are associated not with either of these entities, but rather the relationship between them. The above diagram is inadequate.

2

The first category of items will fall naturally into place when you draw the entire entity-relationship diagram. You can add the second category by converting this many-to-many relationship into an entity.
Employee Employee ID First name Last name Home address Expert In Skill level Date acquired Skill Skill ID is acquired by Skill name Skill description

is capable of

The new entity depends on both the Employee and the Skill entities. It borrows its identifiers from these entities because it depends on both of them. Things to remember ♦ When you are identifying the supporting data, be sure to refer to the activities you identified earlier to see how you will access the data. For example, you may need to list employees by first name in some situations and by last name in others. To accommodate this requirement, create a First Name attribute and a Last Name attribute, rather than a single attribute that contains both names. With the names separate, you can later create two indexes, one suited to each task. ♦ Choose consistent names. Consistency makes it easier to maintain your database and easier to read reports and output windows. For example, if you choose to use an abbreviated name such as Emp_status for one attribute, you should not use a full name, such as Employee_ID, for another attribute. Instead, the names should be Emp_status and Emp_ID. ♦ At this stage, it is not crucial that the data be associated with the correct entity. You can use your intuition. In the next section, you’ll apply tests to check your judgment.

345

The design process

Step 3: Normalize the data
Normalization is a series of tests that eliminate redundancy in the data and make sure the data is associated with the correct entity or relationship. There are five tests. This section presents the first three of them. These three tests are the most important and so the most frequently used.
Why normalize?

The goals of normalization are to remove redundancy and to improve consistency. For example, if you store a customer’s address in multiple locations, it is difficult to update all copies correctly should he move.

$ For more information about the normalization tests, see a book on
database design. Normal forms There are several tests for data normalization. When your data passes the first test, it is considered to be in first normal form. When it passes the second test, it is in second normal form, and when it passes the third test, it is in third normal form.
v To normalize data in a database:

1

List the data. ♦ ♦ ♦ Identify at least one key for each entity. Each entity must have an identifier. Identify keys for relationships. The keys for a relationship are the keys from the two entities that it joins. Check for calculated data in your supporting data list. Calculated data is not normally stored in a relational database.

2

Put data in first normal form. ♦ ♦ If an attribute can have several different values for the same entry, remove these repeated values. Create one or more entities or relationships with the data that you remove.

3

Put data in second normal form. ♦ ♦ ♦ Identify entities and relationships with more than one key. Remove data that depends on only one part of the key. Create one or more entities and relationships with the data that you remove.

4 346

Put data in third normal form.

Chapter 12 Designing Your Database
♦ ♦ Data and identifiers Remove data that depends on other data in the entity or relationship, not on the key. Create one or more entities and relationships with the data that you remove.

Before you begin to normalize (test your design), simply list the data and identify a unique identifier each table. The identifier can be made up of one piece of data (attribute) or several (a compound identifier). The identifier is the set of attributes that uniquely identifies each row in an entity. The identifier for the Employee entity is the Employee ID attribute. The identifier for the Works In relationship consists of the Office Code and Employee ID attributes. You can make an identifier for each relationship in your database by taking the identifiers from each of the entities that it connects. In the following table, the attributes identified with an asterisk are the identifiers for the entity or relationship.
Entity or Relationship Office Attributes *Office code Office address Phone number *Office code *Employee ID *Department ID Department name *Department ID *Employee ID *Department ID *Employee ID *Skill ID Skill name Skill description *Skill ID *Employee ID Skill level Date acquired *Employee ID last name first name Social security number Address phone number date of birth

Works in Department Heads Member of Skill

Expert in

Employee

347

The design process

Putting data in first normal form

♦ ♦

To test for first normal form, look for attributes that can have repeating values. Remove attributes when multiple values can apply to a single item. Move these repeating attributes to a new entity.

In the entity below, Phone number can repeat—an office can have more than one telephone number.
Office and Phone Office code Office address Phone number

Remove the repeating attribute and make a new entity called Telephone. Set up a relationship between Office and Telephone.
Office Office code Office address has Telephone Phone number is located at

Putting data in second normal form

♦ ♦

Remove data that does not depend on the whole key. Look only at entities and relationships whose identifier is composed of more than one attribute. To test for second normal form, remove any data that does not depend on the whole identifier. Each attribute should depend on all of the attributes that comprise the identifier.

In this example, the identifier of the Employee and Department entity is composed of two attributes. Some of the data does not depend on both identifier attributes; for example, the department name depends on only one of those attributes, Department ID, and Employee first name depends only on Employee ID.
Employee and Department Employee ID Department ID Employee first name Employee last name Department name

Move the identifier Department ID, which the other employee data does not depend on, to a entity of its own called Department. Also move any attributes that depend on it. Create a relationship between Employee and Department.

348

Chapter 12 Designing Your Database
Employee Employee ID Employee first name Employee last name works in Department contains Department ID Department name

Putting data in third normal form

♦ ♦

Remove data that doesn’t depend directly on the key. To test for third normal form, remove any attributes that depend on other attributes, rather than directly on the identifier.

In this example, the Employee and Office entity contains some attributes that depend on its identifier, Employee ID. However, attributes such as Office location and Office phone depend on another attribute, Office code. They do not depend directly on the identifier, Employee ID.
Employee and Office Employee ID Employee first name Employee last name Office code Office location Office phone

Remove Office code and those attributes that depend on it. Make another entity called Office. Then, create a relationship that connects Employee with Office.
Employee Employee ID Employee first name Employee last name works out of Office houses Office code Office location Office phone

Step 4: Resolve the relationships
When you finish the normalization process, your design is almost complete. All you need to do is to generate the physical data model that corresponds to your conceptual data model. This process is also known as resolving the relationships, because a large portion of the task involves converting the relationships in the conceptual model into the corresponding tables and foreign-key relationships. Whereas the conceptual model is largely independent of implementation details, the physical data model is tightly bound to the table structure and options available in a particular database application. In this case, that application is Adaptive Server Anywhere. 349

The design process

Resolving relationships that do not carry data

In order to implement relationships that do not carry data, you define foreign keys. A foreign key is a column or set of columns that contains primary key values from another table. The foreign key allows you to access data from more than one table at one time. A database design tool such as the DataArchitect component of Sybase PowerDesigner can generate the physical data model for you. However, if you’re doing it yourself there are some basic rules that help you decide where to put the keys. ♦
One to many An one-to-many relationship always becomes an entity and a foreign key relationship.
Employee Employee Number First Name Last Name Address is a member of Department Department ID Department Name

contains

Notice that entities become tables. Identifiers in entities become (at least part of) the primary key in a table. Attributes become columns. In a oneto-many relationship, the identifier in the one entity will appear as a new foreign key column in the many table.
employee emp_id integer manager_id integer emp_fname char(20) emp_lname char(20) dept_id integer street char(40) city char(20) state char(4) zip_code char(9) phone char(10) status char(1) ss_number char(11) salary numeric(20,3) start_date date termination_date date birth_date date bene_health_ins char(1) bene_life_ins char(1) bene_day_care char(1) sex char(1) department dept_id integer dept_name char(40) dept_head_id integer

dept_id = dept_id

In this example, the Employee entity becomes an Employee table. Similarly, the Department entity becomes a Department table. A foreign key called Department ID appears in the Employee table.

350

Chapter 12 Designing Your Database

One to one In a one-to-one relationship, the foreign key can go into

either table. If the relationship is mandatory on one side, but optional on the other, it should go on the optional side. In this example, put the foreign key (Vehicle ID) in the Truck table because a vehicle does not have to be a truck.
Vehicle Vehicle ID Model Price may be Truck Weight rating is a type of

The above entity-relationship model thus resolves the database base structure, below.
Vehicle Vehicle ID Model Price <pk> Vehicle ID = Vehicle ID Truck Vehicle ID Weight rating <fk>

Many to many In a many-to-many relationship, a new table is created

with two foreign keys. This arrangement is necessary to make the database efficient.
Parts Part Number Description stored at Warehouse contains Warehouse ID Address

The new Storage Location table relates the Parts and Warehouse tables.
Parts Part Number Description <pk>

Storage Location Part Number = Part Number Part Number Warehouse ID <pk,fk> <pk,fk> Warehouse ID = Warehouse ID

Warehouse Warehouse ID Address <pk>

Resolving relationships that carry data

Some of your relationships may carry data. This situation often occurs in many-to-many relationships.

351

The design process
Parts Part Number Description

stored at Inventory Quantity contains Warehouse Warehouse ID Address

If this is the case, each entity resolves to a table. Each role becomes a foreign key that points to another table.
Parts Part Number Description <pk> Inventory Part Number = Part Number Warehouse ID Part Number Quantity <pk,fk> <pk,fk> Warehouse ID = Warehouse ID

Warehouse Warehouse ID <pk> Address

The Inventory entity borrows its identifiers from the Parts and Warehouse tables, because it depends on both of them. Once resolved, these borrowed identifiers form the primary key of the Inventory table.
Tip

A conceptual data model simplifies the design process because it hides a lot of details. For example, a many-to-many relationship always generates an extra table and two foreign key references. In a conceptual data model, you can usually denote all of this structure with a single connection.

Step 5: Verify the design
Before you implement your design, you need to make sure that it supports your needs. Examine the activities you identified at the start of the design process and make sure you can access all of the data that the activities require. ♦ ♦ ♦ Can you find a path to get the information you need? Does the design meet your needs? Is all of the required data available?

If you can answer yes to all the questions above, you are ready to implement your design.

352

Chapter 12 Designing Your Database

Final design

Applying steps 1 through 3 to the database for the little company produces the following entity-relationship diagram. This database is now in third normal form.
Skill is acquired by ID Number Skill name Skill description Department Department ID Department name

Expert In Skill Level Date Acquired

is headed by

manages contains is capable of works out of houses manages Office ID Number Office name Address reports to Employee Employee ID First name Last name Home address

is a member of

The corresponding physical data model appears below.

353

The design process
Skill
ID Number = ID Number

ID Number Skill name Skill description

<pk>

Department Expert In
ID Number Employee ID Skill Level Date Acquired <pk,fk> <pk,fk>
Employee ID = Employee ID

Department ID Employee ID Department name

<pk> <fk>

Department ID = Department ID

Department/Employee Employee
Employee ID = Employee ID

Department ID Employee ID <pk> <fk> <fk>

<pk,fk> <pk,fk>

ID Number = ID Number

Employee ID ID Number Emp_Employee ID First name Last name Home address

Employee ID = Employee ID

Office
ID Number Office name Address <pk>
Employee ID = Emp_Employee ID

354

Chapter 12 Designing Your Database

Designing the database table properties
The database design specifies which tables you have and what columns each table contains. This section describes how to specify each column’s properties. For each column, you must decide the column name, the data type and size, whether or not NULL values are allowed, and whether you want the database to restrict the values allowed in the column.

Choosing column names
A column name can be any set of letters, numbers or symbols. However, you must enclose a column name in double quotes if it contains characters other than letters, numbers, or underscores, if it does not begin with a letter, or if it is the same as a keyword.

Choosing data types for columns
Available data types in Adaptive Server Anywhere include the following: ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ Integer data types Decimal data types Floating-point data types Character data types Binary data types Date/time data types Domains (user-defined data types) Java class data types

$ For a description of data types, see "SQL Data Types" on page 263 of
the book ASA Reference. The long binary data type can be used to store information such as images (for instance, stored as bitmaps) or word-processing documents in a database. These types of information are commonly called binary large objects, or BLOBS.

$ For a complete description of each data type, see "SQL Data Types" on
page 263 of the book ASA Reference. 355

Designing the database table properties

NULL and NOT NULL

If the column value is mandatory for a record, you define the column as being NOT NULL. Otherwise, the column is allowed to contain the NULL value, which represents no value. The default in SQL is to allow NULL values, but you should explicitly declare columns NOT NULL unless there is a good reason to allow NULL values.

$ For a complete description of the NULL value, see "NULL value" on
page 260 of the book ASA Reference. For information on its use in comparisons, see "Search conditions" on page 239 of the book ASA Reference.

Choosing constraints
Although the data type of a column restricts the values that are allowed in that column (for example, only numbers or only dates), you may want to further restrict the allowed values. You can restrict the values of any column by specifying a CHECK constraint. You can use any valid condition that could appear in a WHERE clause to restrict the allowed values. Most CHECK constraints use either the BETWEEN or IN condition.

$ For more information about valid conditions, see "Search conditions"
on page 239 of the book ASA Reference. For more information about assigning constraints to tables and columns, see "Ensuring Data Integrity" on page 357. Example The sample database has a table called Department, which has columns named dept_id, dept_name, and dept_head_id. Its definition is as follows:
Column dept_id dept_name dept_head_id Data Type integer char integer Size — 40 — Null/Not Null not null not null null Constraint None None None

If you specify NOT NULL, a column value must be supplied for every row in the table.

356

C H A P T E R

1 3

Ensuring Data Integrity

About this chapter

Building integrity constraints right into the database is the surest way to make sure your data stays in good shape. This chapter describes the facilities in Adaptive Server Anywhere for ensuring that the data in your database is valid and reliable. You can enforce several types of integrity constraints. For example, you can ensure individual entries are correct by imposing constraints and CHECK conditions on tables and columns. Setting column properties by choosing an appropriate data type or setting special default values assists this task. The SQL statements in this chapter use the CREATE TABLE and ALTER TABLE statements, basic forms of which were introduced in "Working with Database Objects" on page 111.

Contents

Topic Data integrity overview Using column defaults Using table and column constraints Using domains Enforcing entity and referential integrity Integrity rules in the system tables

Page 358 362 367 371 374 379

357

Data integrity overview

Data integrity overview
If data has integrity, it means that the data is valid—correct and accurate— and that the relational structure of the database is intact. Referential integrity constraints enforce the relational structure of the database. These rules maintain the consistency of data between tables. Adaptive Server Anywhere supports stored procedures, which allow you detailed control over how data enters the database. You can also create triggers, or customized stored procedures invoked automatically when a certain action, such as an update of a particular column, occurs.

$ For more information on procedures and triggers see "Using Procedures,
Triggers, and Batches" on page 435.

How data can become invalid
Here are a few examples of how the data in a database may become invalid if proper checks are not made. You can prevent each of these examples from occurring using facilities described in this chapter. Incorrect information ♦ ♦ ♦ ♦ an operator enters the date of a sales transaction incorrectly an employee's salary becomes ten times too small because the operator missed a digit two different people add the same new department (with dept_id 200) to the department table of the organization's database The department identified by dept_id 300 closes down, and one employee record inadvertently remains unassigned to a new department.

Duplicated data Foreign key relations invalidated

Integrity constraints belong in the database
To ensure the validity of data in a database, you need to formulate checks to define valid and invalid data, and design rules to which data must adhere (also known as business rules). Together, checks and rules become constraints. Build integrity constraints into database Constraints built into the database itself are inherently more reliable than those built into client applications or spelled out as instructions to database users. Constraints built into the database become part of the definition of the database itself and the database enforces them consistently across all applications. Setting a constraint once in the database imposes it for all subsequent interactions with the database, no matter from what source.

358

Chapter 13 Ensuring Data Integrity
In contrast, constraints built into client applications are vulnerable every time the software changes, and may need to be imposed in several applications, or in several places in a single client application.

How database contents change
Changes occur to information in database tables when you submit SQL statements from client applications. Only a few SQL statements actually modify the information in a database. You can: ♦ ♦ ♦ Update information in a row of a table using the UPDATE statement. Delete an existing row of a table using the DELETE statement. Insert a new row into a table using the INSERT statement.

Data integrity tools
To assist in maintaining data integrity, you can use defaults, data constraints, and constraints that maintain the referential structure of the database. Defaults You can assign default values to columns to make certain kinds of data entry more reliable. For example: ♦ ♦ A column can have a current date default for recording the date of transactions with any user or client application action. Another type of default allows column values to increment automatically without any specific user action other than entering a new row. With this feature, you can guarantee that items (such as purchase orders for example) are unique, sequential numbers.

$ For more information on these and other column defaults, see "Using
column defaults" on page 362. Constraints You can apply several types of constraints to the data in individual columns or tables. For example: ♦ ♦ A NOT NULL constraint prevents a column from containing a null entry. A CHECK condition assigned to a column can ensure that every item in the column meets a particular condition. For example, you can ensure that salary column entries fit within a specified range and thus protect against user error when typing in new values.

359

Data integrity overview
♦ CHECK conditions can be made on the relative values in different columns. For example, you can ensure that a date_returned entry is later than a date_borrowed entry in a library database. Triggers can enforce more sophisticated CHECK conditions. For more information on triggers, see "Using Procedures, Triggers, and Batches" on page 435.

As well, column constraints can be inherited from domains. For more information on these and other table and column constraints, see "Using table and column constraints" on page 367. Entity and referential integrity Relationships, defined by the primary keys and foreign keys, tie together the information in relational database tables. You must build these relations directly into the database design. The following integrity rules maintain the structure of the database: ♦
Entity integrity

Keeps track of the primary keys. It guarantees that every row of a given table can be uniquely identified by a primary key that guarantees IS NOT NULL. Keeps track of the foreign keys that define the relationships between tables. It guarantees that all foreign key values either match a value in the corresponding primary key or contain the NULL value if they are defined to allow NULL.

Referential integrity

$ For more information about enforcing referential integrity, see
"Enforcing entity and referential integrity" on page 374. For more information about designing appropriate primary and foreign key relations, see "Designing Your Database" on page 333. Triggers for advanced integrity rules You can also use triggers to maintain data integrity. A trigger is a procedure stored in the database and executed automatically whenever the information in a specified table changes. Triggers are a powerful mechanism for database administrators and developers to ensure that data remains reliable.

$ For a full description of triggers, see "Using Procedures, Triggers, and
Batches" on page 435.

SQL statements for implementing integrity constraints
The following SQL statements implement integrity constraints: ♦ ♦
CREATE TABLE statement This statement implements integrity constraints during creation of the database. ALTER TABLE statement This statement adds integrity constraints to an existing database, or modifies constraints for an existing database.

360

Chapter 13 Ensuring Data Integrity

CREATE TRIGGER statement This statement creates triggers that

enforce more complex business rules.

$ For full descriptions of the syntax of these statements, see "SQL
Statements" on page 377 of the book ASA Reference.

361

Using column defaults

Using column defaults
Column defaults automatically assign a specified value to particular columns whenever someone enters a new row into a database table. The default value assigned requires no any action on the part of the client application, however if the client application does specify a value for the column, the new value overrides the column default value. Column defaults can quickly and automatically fill columns with information, such as the date or time a row is inserted, or the user ID of the person entering the information. Using column defaults encourages data integrity, but does not enforce it. Client applications can always override defaults. Supported default values SQL supports the following default values: ♦ ♦ ♦ ♦ ♦ ♦ ♦ A string specified in the CREATE TABLE statement or ALTER TABLE statement A number specified in the CREATE TABLE statement or ALTER TABLE statement An automatically incremented number: one more than the previous highest value in the column The current date, time, or timestamp The current user ID of the database user A NULL value A constant expression, as long as it does not reference database objects.

Creating column defaults
You can use the CREATE TABLE statement to create column defaults at the time a table is created, or the ALTER TABLE statement to add column defaults at a later time. Example The following statement adds a condition to an existing column named id in the sales_order table, so that it automatically increments (unless a client application specifies a value):
ALTER TABLE sales_order MODIFY id DEFAULT AUTOINCREMENT

$ Each of the other default values is specified in a similar manner. For a
detailed description of the syntax, see "CREATE TABLE statement" on page 466 of the book ASA Reference. 362

Chapter 13 Ensuring Data Integrity

Modifying and deleting column defaults
You can change or remove column defaults using the same form of the ALTER TABLE statement you used to create defaults. The following statement changes the default value of a column named order_date from its current setting to CURRENT DATE:
ALTER TABLE sales_order MODIFY order_date DEFAULT CURRENT DATE

You can remove column defaults by modifying them to be NULL. The following statement removes the default from the order_date column:
ALTER TABLE sales_order MODIFY order_date DEFAULT NULL

Working with column defaults in Sybase Central
You can add, alter, and delete column defaults in Sybase Central using the Default tab of the column properties sheet.
v To display the property sheet for a column:

1 2 3 4 5

Connect to the database. Open the Tables folder for that database. Double-click the table holding the column you want to change. Open the Columns folder for that table. Right-click the column and choose Properties from the popup menu.

Current date and time defaults
For columns with the DATE, TIME, or TIMESTAMP data type, you can use the current date, current time, or current timestamp as a default. The default you choose must be compatible with the column’s data type. Useful examples of current date default A current date default might be useful to record: ♦ ♦ ♦ dates of phone calls in a contact database dates of orders in a sales entry database the date a patron borrows a book in a library database

363

Using column defaults

Current timestamp

The current timestamp is similar to the current date default, but offers greater accuracy. For example, a user of a contact management application may have several contacts with a single customer in one day: the current timestamp default would be useful to distinguish these contacts. Since it records a date and the time down to a precision of millionths of a second, you may also find the current timestamp useful when the sequence of events is important in a database.

$ For more information about timestamps, times, and dates, see "SQL
Data Types" on page 263 of the book ASA Reference.

The user ID default
Assigning a DEFAULT USER to a column is an easy and reliable way of identifying the person making an entry in a database. This information may be required, for example, when salespeople are working on commission. Building a user ID default into the primary key of a table is a useful technique for occasionally connected users, and helps to prevent conflicts during information updates. These users can make a copy of tables relevant to their work on a portable computer, make changes while not connected to a multiuser database, and then apply the transaction log to the server when they return.

The AUTOINCREMENT default
The AUTOINCREMENT default is useful for numeric data fields where the value of the number itself may have no meaning. The feature assigns each new row a value of one greater than the previous highest value in the column. You can use AUTOINCREMENT columns to record purchase order numbers, to identify customer service calls or other entries where an identifying number is required. Autoincrement columns are typically primary key columns or columns constrained to hold unique values (see "Enforcing entity integrity" on page 374). For example, an autoincrement default is effective when the column is the first column of an index, because the server uses an index or key definition to find the highest value. While using the autoincrement default in other cases is possible, doing so can adversely affect database performance. For example, in cases where the next value for each column is stored as a long integer (4 bytes), using values greater than (2**31 - 1) or large double or numeric values may cause wraparound to negative values. 364

Chapter 13 Ensuring Data Integrity
You can retrieve the most recent value inserted into an autoincrement column using the @@identity global variable. For more information, see "@@identity global variable" on page 257 of the book ASA Reference. Autoincrement and negative numbers Autoincrement is intended to work with positive integers. The initial autoincrement value is set to 0 when the table is created. This value remains as the highest value assigned when inserts are done that explicitly insert negative values into the column. An insert where no value is supplied causes the AUTOINCREMENT to generate a value of 1, forcing any other generated values to be positive. If only negative values were inserted and the database was stopped and restarted, we would recalculate the highest value for the column and would then start generating negative values. In UltraLite applications, the autoincrement value is not set to 0 when the table is created, and AUTOINCREMENT generates negative numbers when a signed data type is used for the column. You should define AUTOINCREMENT columns as unsigned to prevent negative values from being used. Autoincrement and the IDENTITY column

$ A column with the AUTOINCREMENT default is referred to in
Transact-SQL applications as an IDENTITY column. For information on IDENTITY columns, see "The special IDENTITY column" on page 973.

The NULL default
For columns that allow NULL values, specifying a NULL default is exactly the same as not specifying a default at all. If the client inserting the row does not explicitly assign a value, the row automatically receives A NULL value. You can use NULL defaults when information for some columns is optional or not always available, and when it is not required for the data in the database be correct.

$ For more information on the NULL value, see "NULL value" on
page 260 of the book ASA Reference.

String and number defaults
You can specify a specific string or number as a default value, as long as the column holds a string or number data type. You must ensure that the default specified can be converted to the column’s data type.

365

Using column defaults
Default strings and numbers are useful when there is a typical entry for a given column. For example, if an organization has two offices, the headquarters in city_1 and a small office in city_2, you may want to set a default entry for a location column to city_1, to make data entry easier.

Constant expression defaults
You can use a constant expression as a default value, as long as it does not reference database objects. Constant expressions allow column defaults to contain entries such as the date fifteen days from today, which would be entered as
... DEFAULT ( dateadd( day, 15, getdate() ) )

366

Chapter 13 Ensuring Data Integrity

Using table and column constraints
Along with the basic table structure (number, name and data type of columns, name and location of the table), the CREATE TABLE statement and ALTER TABLE statement can specify many different attributes for a table that allow control over data integrity.
Caution Altering tables can interfere with other users of the database. Although you can execute the ALTER TABLE statement while other connections are active, you cannot execute the ALTER TABLE statement if any other connection is using the table you want to alter. For large tables, ALTER TABLE is a time-consuming operation, and all other requests referencing the table being altered are prohibited while the statement is processing.

This section describes how to use constraints to help ensure the accuracy of data entered in the table.

Using CHECK conditions on columns
You use a CHECK condition to ensure that the values in a column satisfy some definite criterion or rule. For example, these rules or criteria may simply be required for data to be reasonable, or they may be more rigid rules that reflect organization policies and procedures. CHECK conditions on individual column values are useful when only a restricted range of values are valid for that column. Example 1 ♦ You can enforce a particular formatting requirement. For example, if a table has a column for phone numbers you may wish to ensure that users enter them all in the same manner. For North American phone numbers, you could use a constraint such as:
ALTER TABLE customer MODIFY phone CHECK ( phone LIKE ’(___) ___-____’ )

Example 2

You can ensure that the entry matches one of a limited number of values. For example, to ensure that a city column only contains one of a certain number of allowed cities (say, those cities where the organization has offices), you could use a constraint such as:
ALTER TABLE office MODIFY city CHECK ( city IN ( ’city_1’, ’city_2’, ’city_3’ ) )

367

Using table and column constraints
♦ Example 3 ♦ By default, string comparisons are case insensitive unless the database is explicitly created as a case-sensitive database. You can ensure that a date or number falls in a particular range. For example, you may require that the start_date column of an employee table must be between the date the organization was formed and the current date using the following constraint:
ALTER TABLE employee MODIFY start_date CHECK ( start_date BETWEEN ’1983/06/27’ AND CURRENT DATE )

You can use several date formats. The YYYY/MM/DD format in this example has the virtue of always being recognized regardless of the current option settings.

Column CHECK tests only fail if the condition returns a value of FALSE. If the condition returns a value of UNKNOWN, the change is allowed.
Column CHECK conditions in previous releases

There is a change in the way that column CHECK conditions are held in this release. In previous releases, column CHECK conditions were merged together with all other CHECK conditions on a table into a single CHECK condition. Consequently, you could not replace or delete them individually. In this release, column CHECK conditions are held individually in the system tables, and you can replace or delete them individually. Column CHECK conditions added before this release remain under the single table constraint, even if you upgrade the database.

Column CHECK conditions from domains
You can attach CHECK conditions to domains. Columns defined on those data types inherit the CHECK conditions. A CHECK condition explicitly specified for the column overrides that from the domain. Any column defined using the posint data type accepts only positive integers unless the column itself has a CHECK condition explicitly specified. In the following example, the domain accepts only positive integers. Since any variable prefixed with the @ sign is replaced by the name of the column when the CHECK condition is evaluated, any variable name prefixed with @ could be used instead of @col.
CREATE DATATYPE posint INT CHECK ( @col > 0 )

368

Chapter 13 Ensuring Data Integrity
An ALTER TABLE statement with the DELETE CHECK clause deletes all CHECK conditions from the table definition, including those inherited from domains.

$ For information on domains, see "Domains" on page 286 of the book
ASA Reference.

Working with table and column constraints in Sybase Central
You indicate all adding, altering and deleting of column constraints in Sybase Central in the Constraints tab of the table or column property sheet.
v To manage constraints on a table:

1 2 3 4

Open the Tables folder. Right-click the table and choose Properties from the popup menu. Click the Constraints tab. Make the appropriate changes.

v To manage constraints on a column:

1 2 3 4 5

Open the Tables folder and double-click a table to open it. Open the Columns folder. Right-click a column and choose Properties from the popup menu. Click the Constraints tab. Make the appropriate changes.

Using CHECK conditions on tables
A CHECK condition applied as a constraint on the table typically ensures that two values in a row being added or modified have a proper relation to each other. Column CHECK conditions, in contrast, are held individually in the system tables, and you can replace or delete them individually. Since this is more flexible behavior, use CHECK conditions on individual columns where possible. For example, in a library database, the date_borrowed must come before the date_returned.
ALTER TABLE loan ADD CHECK(date_returned >= date_borrowed)

369

Using table and column constraints

Modifying and deleting CHECK conditions
There are several ways to alter the existing set of CHECK conditions on a table. ♦ ♦ You can add a new CHECK condition to the table or to an individual column, as described above. You can delete a CHECK condition on a column by setting it to NULL. For example, the following statement removes the CHECK condition on the phone column in the customer table:
ALTER TABLE customer MODIFY phone CHECK NULL

You can replace a CHECK condition on a column in the same way as you would add a CHECK condition. For example, the following statement adds or replaces a CHECK condition on the phone column of the customer table:
ALTER TABLE customer MODIFY phone CHECK ( phone LIKE ’___-___-____’ )

There are two ways of modifying a CHECK condition defined on the table, as opposed to a CHECK condition defined on a column: ♦ ♦ You can add a new CHECK condition using ALTER TABLE with an ADD table-constraint clause. You can delete all existing CHECK conditions, including column CHECK conditions, using ALTER TABLE DELETE CHECK, and then add in new CHECK conditions.

You can remove all CHECK conditions on a table (including CHECK conditions on all its columns and CHECK conditions inherited from domains) using the ALTER TABLE statement with the DELETE CHECK clause, as follows:
ALTER TABLE table_name DELETE CHECK

Deleting a column from a table does not delete CHECK conditions associated with the column held in the table constraint. Not removing the constraints produces a column not found error message upon any attempt to query data in the table. Table CHECK conditions fail only if a value of FALSE is returned. A value of UNKNOWN allows the change.

370

Chapter 13 Ensuring Data Integrity

Using domains
A domain is a user-defined data type that, together with other attributes, can restrict the range of acceptable values or provide defaults. A domain extends one of the built-in data types. The range of permissible values is usually restricted by a check constraint. In addition, a domain can specify a default value and may or may not allow nulls. You can define your own domains for a number of reasons. ♦ A number of common errors can be prevented if inappropriate values cannot be entered. A constraint placed on a domain ensures that all columns and variables intended to hold values in a desired range or format can hold only the intended values. For example, a data type can ensure that all credit card numbers entered into the database contain the correct number of digits. Domains can make it much easier to understand applications and the structure of a database. Domains can prove convenient. For example, you may intend that all table identifiers are positive integers that, by default, auto-increment. You could enforce this restriction by entering the appropriate constraints and defaults each time you define a new table, but it is less work to define a new domain, then simply state that the identifier can take only values from the specified domain.

♦ ♦

$ For more information about domains, see "SQL Data Types" on
page 263 of the book ASA Reference.

Creating domains (Sybase Central)
You can use Sybase Central to create a domain or assign it to a column.
v To create a new domain (Sybase Central):

1 2 3

Open the Domains folder. In the right pane, double-click Add Domain. Follow the instructions of the wizard.

All domains appear in the Domains folder in Sybase Central.
v To assign domains to columns (Sybase Central):

1

For the desired table, open the Columns folder. 371

Using domains
2 3 Right-click the desired column and choose Properties from the popup menu. On the Data Type tab of the column’s property sheet, assign a domain.

$ For more information, see "Property Sheet Descriptions" on page 1061.

Creating domains (SQL)
You can use the CREATE DOMAIN statement in Interactive SQL to create and define a domain.
v To create a new domain (SQL):

1 2 Example 1: Simple domains

Connect to a database. Execute a CREATE DOMAIN statement.

Some columns in the database are to be used for people’s names and others are to store addresses. You might then define type following domains.
CREATE DOMAIN persons_name CHAR(30) CREATE DOMAIN street_address CHAR(35)

Having defined these domains, you can use them much as you would the built-in data types. For example, you can use these definitions to define a tables as follows.
CREATE TABLE customer ( id INT DEFAULT AUTOINCREMENT name persons_name address street_address ) PRIMARY KEY

Example 2: Default values, check constraints, and identifiers

In the above example, the table’s primary key is specified to be of type integer. Indeed, many of your tables may require similar identifiers. Instead of specifying that these are integers, it is much more convenient to create an identifier domain for use in these applications. When you create a domain, you can specify a default value and provide check constraint to ensure that no inappropriate values are entered into any column of this type. Integer values are commonly used as table identifiers. A good choice for unique identifiers is to use positive integers. Since such identifiers are likely to be used in many tables, you could define the following domain.
CREATE DOMAIN identifier INT DEFAULT AUTOINCREMENT CHECK ( @col > 0 )

372

Chapter 13 Ensuring Data Integrity
This check constraint uses the variable @col. Using this definition, you can rewrite the definition of the customer table, shown above.
CREATE TABLE customer ( id identifier PRIMARY KEY name persons_name address street_address )

Example 3: Built-in domains

Adaptive Server Anywhere comes with some domains pre-defined. You can use these pre-defined domains as you would a domain that you created yourself. For example, the following monetary domain has already been created for you.
CREATE DOMAIN MONEY NUMERIC(19,4) NULL

$ For more information, see "CREATE DOMAIN statement" on
page 433 of the book ASA Reference.

Deleting domains
You can use either Sybase Central or a DROP DOMAIN statement in Interactive SQL to delete a domain. Only the user DBA or the user who created a domain can drop it. In addition, since a domain cannot be dropped if any variable or column in the database is an instance of the domain, you need to first drop any columns or variables of that type before you can drop the domain.
v To delete a domain (Sybase Central):

1 2

Open the Domains folder. Right-click the desired domain and choose Delete from the popup menu.

v To delete a domain (SQL):

1 2 Example

Connect to a database. Execute a DROP DOMAIN statement.

The following statement drops the customer_name domain.
DROP DOMAIN customer_name

$ For more information, see "DROP statement" on page 505 of the book
ASA Reference.

373

Enforcing entity and referential integrity

Enforcing entity and referential integrity
The relational structure of the database enables the personal server to identify information within the database, and ensures all the rows in each table uphold the relationships between tables (described in the database structure).

Enforcing entity integrity
When a user inserts or updates a row, the database server ensures that the primary key for the table is still valid: that each row in the table is uniquely identified by the primary key. Example 1 The employee table in the sample database uses an employee ID as the primary key. When you add a new employee to the table, the database server checks that the new employee ID value is unique and is not NULL. The sales_order_items table in the sample database uses two columns to define a primary key. This table holds information about items ordered. One column contains an id specifying an order, but there may be several items on each order, so this column by itself cannot be a primary key. An additional line_id column identifies which line corresponds to the item. The columns id and line_id, taken together, specify an item uniquely, and form the primary key.

Example 2

If a client application breaches entity integrity
Entity integrity requires that each value of a primary key be unique within the table, and that no NULL values exist. If a client application attempts to insert or update a primary key value, providing values that are not unique would breach entity integrity. A breach in entity integrity prevents the new information from being added to the database, and instead sends the client application an error. The application programmer should decide how to present this information to the user and enable the user to take appropriate action. The appropriate action is usually as simple as asking the user to provide a different, unique value for the primary key.

374

Chapter 13 Ensuring Data Integrity

Primary keys enforce entity integrity
Once you specify the primary key for each table, maintaining entity integrity requires no further action by either client application developers or by the database administrator. The table owner defines the primary key for a table when they create it. If they modify the structure of a table at a later date, they can also redefine the primary key. Some application development systems and database design tools allow you to create and alter database tables. If you are using such a system, you may not have to enter the CREATE TABLE or ALTER TABLE command explicitly: the application may generate the statement itself from the information you provide.

$ For information on creating primary keys, see "Managing primary
keys" on page 131. For the detailed syntax of the CREATE TABLE statement, see "CREATE TABLE statement" on page 466 of the book ASA Reference. For information about changing table structure, see the "ALTER TABLE statement" on page 392 of the book ASA Reference.

Enforcing referential integrity
A foreign key (made up of a particular column or combination of columns) relates the information in one table (the foreign table) to information in another (referenced or primary) table. For the foreign key relationship to be valid, the entries in the foreign key must correspond to the primary key values of a row in the referenced table. Occasionally, some other unique column combination may be referenced instead of a primary key. Example 1 The sample database contains an employee table and a department table. The primary key for the employee table is the employee ID, and the primary key for the department table is the department ID. In the employee table, the department ID is called a foreign key for the department table because each department ID in the employee table corresponds exactly to a department ID in the department table. The foreign key relationship is a many-to-one relationship. Several entries in the employee table have the same department ID entry, but the department ID is the primary key for the department table, and so is unique. If a foreign key could reference a column in the department table containing duplicate entries, or entries with a NULL value, there would be no way of knowing which row in the department table is the appropriate reference. This is a mandatory foreign key.

375

Enforcing entity and referential integrity

Example 2

Suppose the database also contained an office table listing office locations. The employee table might have a foreign key for the office table that indicates which city the employee’s office is in. The database designer can choose to leave an office location unassigned at the time the employee is hired, for example, either because they haven’t been assigned to an office yet, or because they don’t work out of an office. In this case, the foreign key can allow NULL values, and is optional.

Foreign keys enforce referential integrity
Like primary keys, you use the CREATE TABLE or ALTER TABLE statements to create foreign keys. Once you create a foreign key, the column or colums in the key can contain only values that are present as primary key values in the table associated with the foreign key.

$ For information on creating foreign keys, see "Managing primary keys"
on page 131.

Losing referential integrity
Your database can lose referential integrity if someone: ♦ ♦ updates or deletes a primary key value. All the foreign keys referencing that primary key would become invalid. adds a new row to the foreign table, and enters a value for the foreign key that has no corresponding primary key value. The database would become invalid.

Adaptive Server Anywhere provides protection against both types of integrity loss.

If a client application breaches referential integrity
If a client application updates or deletes a primary key value in a table, and if a foreign key references that primary key value elsewhere in the database, there is a danger of a breach of referential integrity. Example If the server allowed the primary key to be updated or deleted, and made no alteration to the foreign keys that referenced it, the foreign key reference would be invalid. Any attempt to use the foreign key reference, for example in a SELECT statement using a KEY JOIN clause, would fail, as no corresponding value in the referenced table exists.

376

Chapter 13 Ensuring Data Integrity
While Adaptive Server Anywhere handles breaches of entity integrity in a generally straightforward fashion by simply refusing to enter the data and returning an error message, potential breaches of referential integrity become more complicated. You have several options (known as referential integrity actions) available to help you maintain referential integrity.

Referential integrity actions
Maintaining referential integrity when updating or deleting a referenced primary key can be as simple as disallowing the update or delete. Often, however, it is also possible to take a specific action on each foreign key to maintain referential integrity. The CREATE TABLE and ALTER TABLE statements allow database administrators and table owners to specify what action to take on foreign keys that reference a modified primary key when a breach occurs. You can specify each of the available referential integrity actions separately for updates and deletes of the primary key: ♦
RESTRICT Generates an error and prevents the modification if an attempt to modify a referenced primary key value occurs. This is the default referential integrity action. SET NULL Sets all foreign keys that reference the modified primary key to NULL. SET DEFAULT

♦ ♦

Sets all foreign keys that reference the modified primary key to the default value for that column (as specified in the table definition).

CASCADE When used with ON UPDATE, this action updates all foreign keys that reference the updated primary key to the new value. When used with ON DELETE, this action deletes all rows containing foreign keys that reference the deleted primary key.

System triggers implement referential integrity actions. The trigger, defined on the primary table, is executed using the permissions of the owner of the secondary table. This behavior means that cascaded operations can take place between tables with different owners, without additional permissions having to be granted.

377

Enforcing entity and referential integrity

Referential integrity checking
For foreign keys defined to RESTRICT operations that would violate referential integrity, default checks occur at the time a statement executes. If you specify a CHECK ON COMMIT clause, then the checks occur only when the transaction is committed. Using a database option to control check time Setting the WAIT_FOR_COMMIT database option controls the behavior when a foreign key is defined to restrict operations that would violate referential integrity. The CHECK ON COMMIT clause can override this option. With the default WAIT_FOR_COMMIT set to OFF, operations that would leave the database inconsistent cannot execute. For example, an attempt to DELETE a department that still has employees in it is not allowed. The following statement gives the error primary key for row in table ’department’ is referenced in another table:
DELETE FROM department WHERE dept_id = 200

Setting WAIT_FOR_COMMIT to ON causes referential integrity to remain unchecked until a commit executes. If the database is in an inconsistent state, the database disallows the commit and reports an error. In this mode, a database user could delete a department with employees in it, however, the user cannot commit the change to the database until they: ♦ ♦ ♦ ♦ Delete or reassign the employees belonging to that department. Redo the search condition on a SELECT statement to select the rows that violate referential integrity. Insert the dept_id row back into the department table. Roll back the transaction to undo the DELETE operation.

378

Chapter 13 Ensuring Data Integrity

Integrity rules in the system tables
All the information about database integrity checks and rules is held in the following system tables:
System table Description The view_def column of SYS.SYSTABLE holds CHECK constraints. For views, the view_def holds the CREATE VIEW command that created the view. You can check whether a particular table is a base table or a view by looking at the table_type column, which is BASE or VIEW. SYS.SYSTRIGGER holds referential integrity actions. The referential_action column holds a single character indicating whether the action is cascade (C), delete (D), set null (N), or restrict (R). The event column holds a single character specifying the event that causes the action to occur: a delete (D), insert (I), update (U), or update of column-list (C). The trigger_time column shows whether the action occurs after (A) or before (B) the triggering event. This view presents the foreign key information from the two tables SYS.SYSFOREIGNKEY and SYS.SYSFKCOL in a more readable format. This view presents the information from the SYS.SYSCOLUMN table in a more readable format. It includes default settings and primary key information for columns.

SYS.SYSTABLE

SYS.SYSTRIGGER

SYS.SYSFOREIGNKEYS

SYS.SYSCOLUMNS

$ For a description of the contents of each system table, see "System
Tables" on page 991 of the book ASA Reference. You can use Sybase Central or Interactive SQL to browse these tables and views.

379

Integrity rules in the system tables

380

C H A P T E R

1 4

Using Transactions and Isolation Levels

About this chapter

You can group SQL statements into transactions, which have the property that either all statements are executed or none is executed. You should design each transaction to perform a task that changes your database from one consistent state to another. This chapter describes transactions and how to use them in applications. It also describes how Adaptive Server Anywhere you can set isolation levels to limit the interference among concurrent transaction.

Contents

Topic Introduction to transactions Isolation levels and consistency Transaction blocking and deadlock Choosing isolation levels Isolation level tutorials How locking works Particular concurrency issues Replication and concurrency Summary

Page 382 386 392 394 398 413 426 428 430

381

Introduction to transactions

Introduction to transactions
To ensure data integrity it is essential that you can identify states in which the information in your database is consistent. The concept of consistency is best illustrated through an example: Consistency: an example Suppose you use your database to handle financial accounts, and you wish to transfer money from one client’s account to another. The database is in a consistent state both before and after the money is transferred; but it is not in a consistent state after you have debited money from one account and before you have credited it to the second. During a transferal of money, the database is in a consistent state when the total amount of money in the clients’ accounts is as it was before any money was transferred. When the money has been half transferred, the database is in an inconsistent state. Either both or neither of the debit and the credit must be processed. A transaction is a logical unit of work. Each transaction is a sequence of logically related commands that accomplish one task and transform the database from one consistent state into another. The nature of a consistent state depends on your database. The statements within a transaction are treated as an indivisible unit: either all are executed or none is executed. At the end of each transaction, you commit your changes to make them permanent. If for any reason some of the commands in the transaction do not process properly, then any intermediate changes are undone, or rolled back. Another way of saying this is that transactions are atomic. Grouping statements into transactions is key both to protecting the consistency of your data even in the event of media or system failure, and to managing concurrent database operations. Transactions may be safely interleaved and the completion of each transaction marks a point at which the information in the database is consistent. In the event of a system failure or database crash during normal operation, Adaptive Server Anywhere performs automatic recovery of your data when the database is next started. The automatic recovery process recovers all completed transactions, and rolls back any transactions that were uncommitted when the failure occurred. The atomic character of transactions ensures that databases are recovered to a consistent state.

Transactions are logical units of work

$ For more information about database backups and data recovery, see
"Backup and Data Recovery" on page 645.

$ For further information about concurrent database usage, see
"Introduction to concurrency" on page 384.

382

Chapter 14 Using Transactions and Isolation Levels

Using transactions
Adaptive Server Anywhere expects you to group your commands into transactions. Knowing which commands or actions signify the start or end of a transaction lets you take full advantage of this feature. Starting transactions Transactions start with one of the following events: ♦ ♦ Completing transactions The first statement following a connection to a database The first statement following the end of a transaction

Transactions complete with one of the following events: ♦ ♦ ♦ A COMMIT statement makes the changes to the database permanent. A ROLLBACK statement undoes all the changes made by the transaction. A statement with a side effect of an automatic commit is executed: data definition commands, such as ALTER, CREATE, COMMENT, and DROP all have the side effect of an automatic commit. A disconnection from a database performs an implicit rollback. ODBC and JDBC have an autocommit setting that enforces a COMMIT after each statement. By default, ODBC and JDBC require autocommit to be on, and each statement is a single transaction. If you want to take advantage of transaction design possibilities, then you should turn autocommit off.

♦ ♦

$ For more information on autocommit, see "Setting autocommit or
manual commit mode" on page 283. ♦ Setting the database option CHAINED to OFF is similar to enforcing an autocommit after each statement. By default, connections that use jConnect or Open Client applications have CHAINED set to OFF.

$ For more information, see "Setting autocommit or manual commit
mode" on page 283, and "CHAINED option" on page 175 of the book ASA Reference. Options in Interactive SQL Interactive SQL lets you control when and how transactions from your application terminate: ♦ If you set the option AUTO_COMMIT to ON, Interactive SQL automatically commits your results following every successful statement and automatically perform a ROLLBACK after each failed statement.

383

Introduction to transactions
♦ The setting of the option COMMIT_ON_EXIT controls what happens to uncommitted changes when you exit Interactive SQL. If this option is set to ON (the default), Interactive SQL does a COMMIT; otherwise it undoes your uncommitted changes with a ROLLBACK statement.

$ Adaptive Server Anywhere also supports Transact-SQL commands
such as BEGIN TRANSACTION, for compatibility with Sybase Adaptive Server Enterprise. For further information, see "Transact-SQL Compatibility" on page 957.

Introduction to concurrency
Concurrency is the ability of the database server to process multiple transactions at the same time. Were it not for special mechanisms within the database server, concurrent transactions could interfere with each other to produce inconsistent and incorrect information. Example A database system in a department store must allow many clerks to update customer accounts concurrently. Each clerk must be able to update the status of the accounts as they assist each customer: they cannot afford to wait until no one else is using the database. Concurrency is a concern to all database administrators and developers. Even if you are working with a single-user database, you must be concerned with concurrency if you wish to process instructions from multiple applications or even from multiple connections from a single application. These applications and connections can interfere with each other in exactly the same way as multiple users in a network setting. The way you group SQL statements into transactions can have significant effects on data integrity and on system performance. If you make a transaction too short and it does not contain an entire logical unit of work, then inconsistencies can be introduced into the database. If you write a transaction that is too long and contains several unrelated actions, then there is greater chance that a ROLLBACK will unnecessarily undo work that could have been committed quite safely into the database. If your transactions are long, they can lower concurrency by preventing other transactions from being processed concurrently. There are many factors that determine the appropriate length of a transaction, depending on the type of application and the environment.

Who needs to know about concurrency

Transaction size affects concurrency

384

Chapter 14 Using Transactions and Isolation Levels

Savepoints within transactions
You may identify important states within a transaction and return to them selectively by using savepoints to separate groups of related statements. A SAVEPOINT statement defines an intermediate point during a transaction. You can undo all changes after that point using a ROLLBACK TO SAVEPOINT statement. Once a RELEASE SAVEPOINT statement has been executed or the transaction has ended, you can no longer use the savepoint. No locks are released by the RELEASE SAVEPOINT or ROLLBACK TO SAVEPOINT commands: locks are released only at the end of a transaction. Naming and nesting savepoints By using named, nested savepoints, you can have many active savepoints within a transaction. Changes between a SAVEPOINT and a RELEASE SAVEPOINT can be canceled by rolling back to a previous savepoint or rolling back the transaction itself. Changes within a transaction are not a permanent part of the database until the transaction is committed. All savepoints are released when a transaction ends. Savepoints cannot be used in bulk operations mode. There is very little additional overhead in using savepoints.

385

Isolation levels and consistency

Isolation levels and consistency
There are four isolation levels Adaptive Server Anywhere allows you to control the degree to which the operations in one transaction are visible to the operations in other concurrent transactions. You do so by setting a database option called the isolation level. Adaptive Server Anywhere has four different isolation levels (numbered 0 through 3) that prevent some or all inconsistent behavior. Level 3 provides the highest level of isolation. Lower levels allow more inconsistencies, but typically have better performance. Level 0 is the default setting. All isolation levels guarantee that each transaction will execute completely or not at all, and that no updates will be lost.

Typical types of inconsistency
There are three typical types of inconsistency that can occur during the execution of concurrent transactions. This list is not exhaustive as other types of inconsistencies can also occur. These three types are mentioned in the ISO SQL/92 standard and are important because behavior at lower isolation levels is defined in terms of them. ♦
Dirty read Transaction A modifies a row, but does not commit or roll back the change. Transaction B reads the modified row. Transaction A then either further changes the row before performing a COMMIT, or rolls back its modification. In either case, transaction B has seen the row in a state which was never committed.

$ For an example of how isolation levels create dirty reads, see
"Tutorial 1: The dirty read" on page 398. ♦
Non-repeatable read

Transaction A reads a row. Transaction B then modifies or deletes the row and performs a COMMIT. If transaction A then attempts to read the same row again, the row will have been changed or deleted. non-repeatable read" on page 401.

$ For an example of a non-repeatable read, see "Tutorial 2 – The

Phantom row

Transaction A reads a set of rows that satisfy some condition. Transaction B then executes an INSERT, or an UPDATE on a row which did not previously meet A's condition. Transaction B commits these changes. These newly committed rows now satisfy the condition. Transaction A then repeats the initial read and obtains a different set of rows.

386

Chapter 14 Using Transactions and Isolation Levels

$ For an example of a phantom row, see "Tutorial 3 – A phantom
row" on page 405. Other types of inconsistencies can also exist. These three were chosen for the ISO SQL/92 standard because they are typical problems and because it was convenient to describe amounts of locking between transactions in terms of them. Isolation levels and dirty reads, nonrepeatable reads, and phantom rows The isolation levels are different with respect to the type of inconsistent behaviour that Adaptive Server Anywhere allows. An x means that the behavior is prevented, and a á means that the behavior may occur.
Isolation level 0 1 2 3 Dirty reads Non-repeatable reads Phantom rows

á
x x x

á á
x x

á á á
x

This table demonstrates two points: ♦ ♦ Each isolation level eliminates one of the three typical types of inconsistencies. Each level eliminates the types of inconsistencies eliminated at all lower levels.

The four isolation levels have different names under ODBC. These names are based on the names of the inconsistencies that they prevent, and are described in "The ValuePtr parameter" on page 389.

Cursor instability
Another significant inconsistency is cursor instability. When this inconsistency is present, a transaction can modify a row that is being referenced by another transaction's cursor. Example Transaction A reads a row using a cursor. Transaction B modifies that row. Not realizing that the row has been modified, Transaction A modifies it, rendering the affected row's data incorrect.

387

Isolation levels and consistency

Eliminating cursor instability

Adaptive Server Anywhere achieves cursor stability at isolation levels 1, 2, and 3. Cursor stability ensures that no other transactions can modify information that is contained in the present row of your cursor. The information in a row of a cursor may be the copy of information contained in a particular table or may be a combination of data from different rows of multiple tables. More than one table will likely be involved whenever you use a join or sub-selection within a SELECT statement.

$ For information on programming SQL procedures and cursors, see
"Using Procedures, Triggers, and Batches" on page 435.

$ Cursors are used only when you are using Adaptive Server Anywhere
through another application. For more information, see "Using SQL in Applications" on page 263.

Setting the isolation level
Each connection to the database has its own isolation level. In addition, the database can store a default isolation level for each user or group. The PUBLIC setting enables you to set a single default isolation level for the entire database’s group. The isolation level is a database option. You change database options using the SET OPTION statement. For example, the following command sets the isolation level for the current user to 3, the highest level.
SET OPTION ISOLATION_LEVEL = 3

You can change the isolation of your connection and the default level associated with your user ID using the SET OPTION command. If you have permission, you can also change the isolation level for other users or groups.
v To set the isolation level for the current user ID:

Execute the SET OPTION statement. For example, the following statement sets the isolation level to 3 for the current user:
SET TEMPORARY OPTION ISOLATION_LEVEL = 3

v To set the isolation level for a user or group:

1 2

Connect to the database as a user with DBA authority. Execute the SET OPTION statement, adding the name of the group and a period before ISOLATION_LEVEL. For example, the following command sets the default isolation for the special group PUBLIC to 3.
SET OPTION PUBLIC.ISOLATION_LEVEL = 3

388

Chapter 14 Using Transactions and Isolation Levels
v To set the isolation level just for your present session:

Execute the SET OPTION statement using the TEMPORARY keyword. For example, the following statement sets the isolation level to 3 for the duration of your connection:
SET TEMPORARY OPTION ISOLATION_LEVEL = 3

Once you disconnect, your isolation level reverts to its previous value. Default isolation level When you connect to a database, the database server determines your initial isolation level as follows: 1 2 A default isolation level may be set for each user and group. If a level is stored in the database for your user ID, then the database server uses it. If not, the database server checks the groups to which you belong until it finds a level. All users are members of the special group PUBLIC. If it finds no other setting first, then Adaptive Server Anywhere will use the level assigned to that group.

$ For further information about users and groups, please refer to
"Managing User IDs and Permissions" on page 735.

$ For a description of the SET OPTION statement syntax, see "SET
OPTION statement" on page 612 of the book ASA Reference.

$ You may wish to change the isolation level in mid-transaction if, for
example, just one table or group of tables requires serialized access. For information about changing the isolation level within a transaction, see "Changing the isolation level within a transaction" on page 390.

Setting the isolation level from an ODBC-enabled application
ODBC applications call SQLSetConnectAttr with Attribute set to SQL_ATTR_TXN_ISOLATION and ValuePtr set according to the corresponding isolation level: The ValuePtr parameter
ValuePtr SQL_TXN_READ_UNCOMMITTED SQL_TXN_READ_COMMITTED SQL_TXN_REPEATABLE_READ SQL_TXT_SERIALIZABLE Isolation Level 0 1 2 3

Changing an isolation level via ODBC

You can change the isolation level of your connection via ODBC by using the function SQLSetConnectOption in the library ODBC32.dll.

389

Isolation levels and consistency
The SQLSetConnectOption function reads three parameters: the value of the ODBC connection handle, the fact that you wish to set the isolation level, and the value corresponding to the isolation level. These values appear in the table below.
String SQL_TXN_ISOLATION SQL_TXN_READ_UNCOMMITTED SQL_TXN_READ_COMMITTED SQL_TXN_REPEATABLE_READ SQL_TXT_SERIALIZABLE Value 108 1 2 4 8

Example

The following function call sets the isolation level of the connection MyConnection to isolation level 2: ODBC uses the isolation feature to support assorted database lock options. For example, in PowerBuilder you can use the Lock attribute of the transaction object to set the isolation level when you connect to the database. The Lock attribute is a string, and is set as follows:
SQLCA.lock = "RU"

SQLSetConnectOption(MyConnection.hDbc, SQL_TXN_ISOLATION, SQL_TXN_REPEATABLE_READ)

The Lock option is honored only at the moment the CONNECT occurs. Changes to the Lock attribute after the CONNECT have no effect on the connection.

Changing the isolation level within a transaction
Sometimes you will find that different isolation levels are suitable for different parts of a single transaction. Adaptive Server Anywhere allows you to change the isolation level of your database in the middle of a transaction. When you change the ISOLATION_LEVEL option in the middle of a transaction, the new setting affects only the following: ♦ ♦ Any cursors opened after the change Any statements executed after the change

You may wish to change the isolation level during a transaction, as doing so affords you control over the number of locks your transaction places. You may find a transaction needs to read a large table, but perform detailed work with only a few of the rows. If an inconsistency would not seriously affect your transaction, set the isolation to a low level while you scan the large table to avoid delaying the work of others. 390

Chapter 14 Using Transactions and Isolation Levels
You may also wish to change the isolation level in mid transaction if, for example, just one table or group of tables requires serialized access.

$ For an example in which the isolation level is changed in the middle of
a transaction, see "Tutorial 3 – A phantom row" on page 405.

Viewing the isolation level
You can inspect the isolation level of the current connection using the CONNECTION_PROPERTY function.
v To view the isolation level for the current connection:

Execute the following statement:
SELECT CONNECTION_PROPERTY(’ISOLATION_LEVEL’)

391

Transaction blocking and deadlock

Transaction blocking and deadlock
When a transaction is being executed, the database server places locks on rows to prevent other transactions from interfering with the affected rows. Locks can interfere with other transactions that are trying to access the locked rows. Adaptive Server Anywhere uses transaction blocking to allow transactions to execute concurrently without interference, or with limited interference. Any transaction can acquire a lock to prevent other concurrent transactions from modifying or even accessing a particular row. This transaction blocking scheme always stops some types of interference. For example, a transaction that is updating a particular row of a table always acquires a lock on that row to ensure that no other transaction can update or delete the same row at the same time.

Transaction blocking
When a transaction attempts to carry out an operation, but is forbidden by a lock held by another transaction, a conflict arises and the progress of the transaction attempting to carry out the operation is impeded or blocked.

$ "Two-phase locking" on page 422 describes deadlock, which occurs
when two or more transactions are blocked by each other in such a way that none can proceed.

$ Sometimes a set of transactions arrive at a state where none of them can
proceed. For more information see "Deadlock" on page 393.

The BLOCKING option
If two transactions have each acquired a read lock on a single row, the behavior when one of them attempts to modify that row depends on the database setting BLOCKING. To modify the row, that transaction must block the other, yet it cannot do so while the other transaction has it blocked. ♦ If BLOCKING is ON (the default setting), then the transaction that attempts to write waits until the other transaction releases its read lock. At that time, the write goes through. If BLOCKING has been set to OFF, then the transaction that attempts to write receives an error.

392

Chapter 14 Using Transactions and Isolation Levels
When BLOCKING is set to OFF, the transaction terminates instead of waiting and any changes it has made are rolled back. In this event, try executing the transaction again, later. Blocking is more likely to occur at higher isolation levels because more locking and more checking is done. Higher isolation levels usually provide less concurrency. How much less depends on the individual natures of the concurrent transactions.

$ For information about the BLOCKING option, see "BLOCKING
option" on page 175 of the book ASA Reference.

Deadlock
Transaction blocking can lead to deadlock, a situation in which a set of transactions arrive at a state where none of them can proceed. Reasons for deadlocks A deadlock can arise for two reasons: ♦
A cyclical blocking conflict Transaction A is blocked on transaction

B, and transaction B is blocked on transaction A. Clearly, more time will not solve the problem, and one of the transactions must be canceled, allowing the other to proceed. The same situation can arise with more than two transactions blocked in a cycle. ♦
All active database threads are blocked When a transaction becomes

blocked, its database thread is not relinquished. If the database is configured with three threads and transactions A, B, and C are blocked on transaction D which is not currently executing a request, then a deadlock situation has arisen since there are no available threads. Adaptive Server Anywhere automatically cancels the last transaction that became blocked (eliminating the deadlock situation), and returns an error to that transaction indicating which form of deadlock occurred.

$ The number of database threads that the server uses depends on the
individual database’s setting. For information on setting the number of database threads, see "THREAD_COUNT option" on page 213 of the book ASA Reference and "–ge command-line option" on page 27 of the book ASA Reference. Determining who is blocked You can use the sa_conn_info system procedure to determine which connections are blocked on which other connections. This procedure returns a result set consisting of a row for each connection. One column of the result set lists whether the connection is blocked, and if so which other connection it is blocked on.

$ For more information, see "sa_conn_info system procedure" on
page 964 of the book ASA Reference. 393

Choosing isolation levels

Choosing isolation levels
The choice of isolation level depends on the kind of task an application is carrying out. This section gives some guidelines for choosing isolation levels. When you choose an appropriate isolation level you must balance the need for consistency and accuracy with the need for concurrent transactions to proceed unimpeded. If a transaction involves only one or two specific values in one table, it is unlikely to interfere as much with other processes as one which searches many large tables and may need to lock many rows or entire tables and may take a very long time to complete. For example, if your transactions involve transferring money between bank accounts or even checking account balances, you will likely want to do your utmost to ensure that the information you return is correct. On the other hand, if you just want a rough estimate of the proportion of inactive accounts, then you may not care whether your transaction waits for others or not and indeed may be willing to sacrifice some accuracy to avoid interfering with other users of the database. Furthermore, a transfer may affect only the two rows which contain the two account balances, whereas all the accounts must be read in order to calculate the estimate. For this reason, the transfer is less likely to delay other transactions. Adaptive Server Anywhere provides four levels of isolation: levels 0, 1, 2, and 3. Level 3 provides complete isolation and ensures that transactions are interleaved in such a manner that the schedule is serializable.

Serializable schedules
To process transactions concurrently, the database server must execute some component statements of one transaction, then some from other transactions, before continuing to process further operations from the first. The order in which the component operations of the various transactions are interleaved is called the schedule. Applying transactions concurrently in this manner can result in many possible outcomes, including the three particular inconsistencies described in the previous section. Sometimes, the final state of the database also could have been achieved had the transactions been executed sequentially, meaning that one transaction was always completed in its entirety before the next was started. A schedule is called serializable whenever executing the transactions sequentially, in some order, could have left the database in the same state as the actual schedule. 394

Chapter 14 Using Transactions and Isolation Levels

$ For information about how Adaptive Server Anywhere handles
serialization, see "Two-phase locking" on page 422. Serializability is the commonly accepted criterion for correctness. A serializable schedule is accepted as correct because the database is not influenced by the concurrent execution of the transactions. The isolation level affects a transaction’s serializability. At isolation level 3, all schedules are serializable. The default setting is 0. Serializable means that concurrency has added no effect Even when transactions are executed sequentially, the final state of the database can depend upon the order in which these transactions are executed. For example, if one transaction sets a particular cell to the value 5 and another sets it to the number 6, then the final value of the cell is determined by which transaction executes last. Knowing a schedule is serializable does not settle which order transactions would best be executed, but rather states that concurrency has added no effect. Outcomes which may be achieved by executing the set of transactions sequentially in some order are all assumed correct. Unserializable schedules introduce inconsistencies The inconsistencies introduced in "Typical types of inconsistency" on page 386 are typical of the types of problems that appear when the schedule is not serializable. In each case, the inconsistency appeared because the statements were interleaved in such a way as to produce a result that would not be possible if all transactions were executed sequentially. For example, a dirty read can only occur if one transaction can select rows while another transaction is in the middle of inserting or updating data in the same row.

Typical transactions at various isolation levels
Various isolation levels lend themselves to particular types of tasks. Use the information below to help you decide which level is best suited to each particular operation. Typical level 0 transactions Transactions that involve browsing or performing data entry may last several minutes, and read a large number of rows. If isolation level 2 or 3 is used, concurrency can suffer. Isolation level of 0 or 1 is typically used for this kind of transaction. For example, a decision support application that reads large amounts of information from the database to produce statistical summaries may not be significantly affected if it reads a few rows that are later modified. If high isolation is required for such an application, it may acquire read locks on large amounts of data, not allowing other applications write access to it.

395

Choosing isolation levels

Typical level 1 transactions

Isolation level 1 is particularly useful in conjunction with cursors, because this combination ensures cursor stability without greatly increasing locking requirements. Adaptive Server Anywhere achieves this benefit through the early release of read locks acquired for the present row of a cursor. These locks must persist until the end of the transaction at either levels two or three in order to guarantee repeatable reads. For example, a transaction that updates inventory levels through a cursor is particularly suited to this level, because each of the adjustments to inventory levels as items are received and sold would not be lost, yet these frequent adjustments would have minimal impact on other transactions.

Typical level 2 transactions

At isolation level 2, rows that match your criterion cannot be changed by other transactions. You can thus employ this level when you must read rows more than once and rely that rows contained in your first result set won’t change. Because of the relatively large number of read locks required, you should use this isolation level with care. As with level 3 transactions, careful design of your database and indexes reduce the number of locks acquired and hence can improve the performance of your database significantly.

Typical level 3 transactions

Isolation level 3 is appropriate for transactions that demand the most in security. The elimination of phantom rows lets you perform multi-step operations on a set of rows without fear that new rows will appear partway through your operations and corrupt the result. However much integrity it provides, isolation level 3 should be used sparingly on large systems that are required to support a large number of concurrent transactions. Adaptive Server Anywhere places more locks at this level than at any other, raising the likelihood that one transaction will impede the process of many others.

Improving concurrency at isolation levels 2 and 3
Isolation levels 2 and 3 use a lot of locks and so good design is of particular importance for databases that make regular use of these isolation levels. When you must make use of serializable transactions, it is important that you design your database, in particular the indices, with the business rules of your project in mind. You may also improve performance by breaking large transactions into several smaller ones, thus shortening the length of time that rows are locked.

396

Chapter 14 Using Transactions and Isolation Levels
Although serializable transactions have the most potential to block other transactions, they are not necessarily less efficient. When processing these transactions, Adaptive Server Anywhere can perform certain optimizations that may improve performance, in spite of the increased number of locks. For example, since all rows read must be locked whether or not they match the a search criteria, the database server is free to combine the operation of reading rows and placing locks.

Reducing the impact of locking
You should avoid running transactions at isolation level 3 whenever practical. They tend to place large number of locks and hence impact the efficient execution of other concurrent transactions. When the nature of an operation demands that it run at isolation level 3, you can lower its impact on concurrency by designing the query to read as few rows and index entries as possible. These steps will help the level 3 transaction run more quickly and, of possibly greater importance, will reduce the number of locks it places. In particular, you may find that adding an index may greatly help speed up transactions, particularly when at least one of them must execute at isolation level 3. An index can have two benefits: ♦ ♦ An index enables rows to be located in an efficient manner Searches that make use of the index may need fewer locks.

$ Further information on the details of the locking methods employed by
Adaptive Server Anywhere is located in "How locking works" on page 413.

$ For information on performance and how Adaptive Server Anywhere
plans its access of information to execute your commands, see "Monitoring and Improving Performance" on page 799.

397

Isolation level tutorials

Isolation level tutorials
The different isolation levels behave in very different ways, and which one you will want to use depends on your database and on the operations you are carrying out. The following set of tutorials will help you determine which isolation levels are suitable for different tasks.

Tutorial 1: The dirty read
The following tutorial demonstrates one type of inconsistency that can occur when multiple transactions are executed concurrently. Two employees at a typical small merchandising company both access the corporate database at the same time. The first person is the company’s Sales Manager. The second is the Accountant. The Sales Manager wants to increase the price of one of the tee shirts sold by their firm by $0.95, but is having a little trouble with the syntax of the SQL language. At the same time, unknown to the Sales Manager, the Accountant is trying to calculate the retail value of the current inventory to include in a report he volunteered to bring to the next management meeting. In this example, you will play the role of two people, both using the demonstration database concurrently. 1 2 Start Interactive SQL. Connect to the sample database as the Sales Manager. In the Connect dialog, choose the ODBC data source ASA 7.0 Sample. On the Advanced tab, enter the following string to make the window easier to identify:
ConnectionName=Sales Manager

Click OK to connect. 3 4 Start a second copy of Interactive SQL. Connect to the sample database as the Accountant. In the Connect dialog, choose the ODBC data source ASA 7.0 Sample. On the Advanced tab, enter the following string to make the window easier to identify:
ConnectionName=Accountant

Click OK to connect. 5 398 As the Sales Manager, raise the price of all the tee shirts by $0.95.

Chapter 14 Using Transactions and Isolation Levels
In the window labeled Sales Manager, execute the following commands:
SELECT id, name, unit_price FROM product; UPDATE PRODUCT SET unit_price = unit_price + 95 WHERE NAME = ’Tee Shirt’

The result is:
id 300 301 302 400 401 500 501 600 601 700 name Tee Shirt Tee Shirt Tee Shirt Baseball Cap Baseball Cap Visor Visor Sweatshirt Sweatshirt Shorts unit_price 104.00 109.00 109.00 9.00 10.00 7.00 7.00 24.00 24.00 15.00

You observe immediately that you should have entered 0.95 instead of 95, but before you can fix your error, the Accountant accesses the database from another office. 6 The company’s Accountant is worried that too much money is tied up in inventory. As the Accountant, execute the following commands to calculate the total retail value of all the merchandise in stock:
SELECT SUM( quantity * unit_price ) AS inventory FROM product

The result is:
inventory 21453.00

399

Isolation level tutorials
Unfortunately, this calculation is not accurate. The Sales Manager accidentally raised the price of the visor $95, and the result reflects this erroneous price. This mistake demonstrates one typical type of inconsistency known as a dirty read. You, as the Accountant, accessed data which the Sales Manager has entered, but has not yet committed.

$ You can eliminate dirty reads and other inconsistencies explained
in "Isolation levels and consistency" on page 386. 7 As the Sales Manager, fix the error by rolling back your first changes and entering the correct UPDATE command. Check that your new values are correct.
ROLLBACK; UPDATE product SET unit_price = unit_price + 0.95 WHERE NAME = ’Tee Shirt’; id 300 301 302 400 401 500 501 600 601 700 name Tee Shirt Tee Shirt Tee Shirt Baseball Cap Baseball Cap Visor Visor Sweatshirt Sweatshirt Shorts unit_price 9.95 14.95 14.95 9.00 10.00 7.00 7.00 24.00 24.00 15.00

8

The Accountant does not know that the amount he calculated was in error. You can see the correct value by executing his SELECT statement again in his window.
SELECT SUM( quantity * unit_price ) AS inventory FROM product; inventory 6687.15

400

Chapter 14 Using Transactions and Isolation Levels
9 Finish the transaction in the Sales Manager’s window. She would enter a COMMIT statement to make his changes permanent, but you may wish to enter a ROLLBACK, instead, to avoid changing the copy of the demonstration database on your machine.
ROLLBACK;

The Accountant unknowingly receives erroneous information from the database because the database server is processing the work of both the Sales Manager and the Accountant concurrently.

Tutorial 2 – The non-repeatable read
The example in section "Introduction to concurrency" on page 384 demonstrated the first type of inconsistency, namely the dirty read. In that example, an Accountant made a calculation while the Sales Manager was in the process of updating a price. The Accountant’s calculation used erroneous information which the Sales Manager had entered and was in the process of fixing. The following example demonstrates another type of inconsistency: nonrepeatable reads. In this example, you will play the role of the same two people, both using the demonstration database concurrently. The Sales Manager wishes to offer a new sales price on plastic visors. The Accountant wishes to verify the prices of some items that appear on a recent order. This example begins with both connections at isolation level 1, rather than at isolation level 0, which is the default for the demonstration database supplied with Adaptive Server Anywhere. By setting the isolation level to 1, you eliminate the type of inconsistency which the previous tutorial demonstrated, namely the dirty read. 1 2 Start Interactive SQL. Connect to the sample database as the Sales Manager. In the Connect dialog, choose the ODBC data source ASA 7.0 Sample. On the Advanced tab, enter the following string to make the window easier to identify:
ConnectionName=Sales Manager

Click OK to connect. 3 4 Start a second copy of Interactive SQL. Connect to the sample database as the Accountant. In the Connect dialog, choose the ODBC data source ASA 7.0 Sample.

401

Isolation level tutorials
On the Advanced tab, enter the following string to make the window easier to identify:
ConnectionName=Accountant

Click OK to connect. 5 Set the isolation level to 1 for the Accountant’s connection by executing the following command.
SET TEMPORARY OPTION ISOLATION_LEVEL = 1;

6

Set the isolation level to 1 in the Sales Manager’s window by executing the following command:
SET TEMPORARY OPTION ISOLATION_LEVEL = 1;

7

The Accountant decides to list the prices of the visors. As the Accountant, execute the following command:
SELECT id, name, unit_price FROM product id 300 301 302 400 401 500 501 name Tee Shirt Tee Shirt Tee Shirt Baseball Cap Baseball Cap Visor Visor unit_price 9.00 14.00 14.00 9.00 10.00 7.00 7.00

8

The Sales Manager decides to introduce a new sale price for the plastic visor. As the Sales Manager, execute the following command:
SELECT id, name, unit_price FROM product WHERE name = ’Visor’; UPDATE product SET unit_price = 5.95 WHERE id = 501; COMMIT; id 500 501 name Visor Visor unit_price 7.00 5.95

402

Chapter 14 Using Transactions and Isolation Levels
9 Compare the price of the visor in the Sales Manager window with the price for the same visor in the Accountant window. The Accountant window still shows the old price, even though the Sales Manager has entered the new price and committed the change. This inconsistency is called a non-repeatable read, because if the Accountant did the same select a second time in the same transaction, he wouldn’t get the same results. Try it for yourself. As the Accountant, execute the select command again. Observe that the Sales Manager’s sale price now displays.
SELECT id, name, price FROM products; id 300 301 302 400 401 500 501 name Tee Shirt Tee Shirt Tee Shirt Baseball Cap Baseball Cap Visor Visor unit_price 9.00 14.00 14.00 9.00 10.00 7.00 5.95

Of course if the Accountant had finished his transaction, for example by issuing a COMMIT or ROLLBACK command before using SELECT again, it would be a different matter. The database is available for simultaneous use by multiple users and it is completely permissible for someone to change values either before or after the Accountant’s transaction. The change in results is only inconsistent because it happens in the middle of his transaction. Such an event makes the schedule unserializable. 10 The Accountant notices this behavior and decides that from now on he doesn’t want the prices changing while he looks at them. Repeatable reads are eliminated at isolation level 2. Play the role of the Accountant:
SET TEMPORARY OPTION ISOLATION_LEVEL = 2; SELECT id, name, unit_price FROM product;

11 The Sales Manager decides that it would be better to delay the sale on the plastic visor until next week so that she won’t have to give the lower price on a big order that she’s expecting will arrive tomorrow. In her window, try to execute the following statements. The command will start to execute, then his window will appear to freeze. 403

Isolation level tutorials
UPDATE product SET unit_price = 7.00 WHERE id = 501

The database server must guarantee repeatable reads at isolation level 2. To do so, it places a read lock on each row of the product table that the Accountant reads. When the Sales Manager tries to change the price back, her transaction must acquire a write lock on the plastic visor row of the product table. Since write locks are exclusive, her transaction must wait until the Accountant’s transaction releases its read lock. 12 The Accountant is finished looking at the prices. He doesn’t want to risk accidentally changing the database, so he completes his transaction with a ROLLBACK statement.
ROLLBACK

Observe that as soon as the database server executes this statement, the Sales Manager’s transaction completes.
id 500 501 name Visor Visor unit_price 7.00 7.00

13 The Sales Manager can finish now. She wishes to commit her change to restore the original price.
COMMIT

Types of Locks and different isolation levels

When you upgraded the Accountant’s isolation from level 1 to level 2, the database server used read locks where none had previously been acquired. In general, each isolation level is characterized by the types of locks needed and by how locks held by other transactions are treated. At isolation level 0, the database server needs only write locks. It makes use of these locks to ensure that no two transactions make modifications that conflict. For example, a level 0 transaction acquires a write lock on a row before it updates or deletes it, and inserts any new rows with a write lock already in place. Level 0 transactions perform no checks on the rows they are reading. For example, when a level 0 transaction reads a row, it doesn’t bother to check what locks may or may not have been acquired on that row by other transactions. Since no checks are needed, level 0 transactions are particularly fast. This speed comes at the expense of consistency. Whenever they read a row which is write locked by another transaction, they risk returning dirty data.

404

Chapter 14 Using Transactions and Isolation Levels
At level 1, transactions check for write locks before they read a row. Although one more operation is required, these transactions are assured that all the data they read is committed. Try repeating the first tutorial with the isolation level set to 1 instead of 0. You will find that the Accountant’s computation cannot proceed while the Sales Manager’s transaction, which updates the price of the tee shirts, remains incomplete. When the Accountant raised his isolation to level 2, the database server began using read locks. From then on, it acquired a read lock for his transaction on each row that matched his selection. Transaction blocking In step 10 of the above tutorial, the Sales Manager window froze during the execution of her UPDATE command. The database server began to execute her command, then found that the Accountant’s transaction had acquired a read lock on the row that the Sales Manager needed to change. At this point, the database server simply paused the execution of the UPDATE. Once the Accountant finished his transaction with the ROLLBACK, the database server automatically released his locks. Finding no further obstructions, it then proceeded to complete execution of the Sales Manager’s UPDATE. In general, a locking conflict occurs when one transaction attempts to acquire an exclusive lock on a row on which another transaction holds a lock, or attempts to acquire a shared lock on a row on which another transaction holds an exclusive lock. One transaction must wait for another transaction to complete. The transaction that must wait is said to be blocked by another transaction. When the database server identifies a locking conflict which prohibits a transaction from proceeding immediately, it can either pause execution of the transaction, or it can terminate the transaction, roll back any changes, and return an error. You control the route by setting the BLOCKING option. When BLOCKING is set to ON, then the second transaction waits as in the above tutorial

$ For further information regarding the blocking option, see "The
BLOCKING option" on page 392.

Tutorial 3 – A phantom row
The following continues the same scenario. In this case, the Accountant views the department table while the Sales Manager creates a new department. You will observe the appearance of a phantom row. If you have not done so, do steps 1 through 4 of the previous tutorial, "Tutorial 2 – The non-repeatable read" on page 401. These steps describe how to open two copies of Interactive SQL.

405

Isolation level tutorials
1 Set the isolation level to 2 in the Sales Manager window by executing the following command.
SET TEMPORARY OPTION ISOLATION_LEVEL = 2;

2

Set the isolation level to 2 for the Accountant window by executing the following command.
SET TEMPORARY OPTION ISOLATION_LEVEL = 2;

3

In the Accountant window, enter the following command to list all the departments.
SELECT * FROM department ORDER BY dept_id; dept_id 100 200 300 400 500 dept_name R&D Sales Finance Marketing Shipping dept_head_id 501 902 1293 1576 703

4

The Sales Manager decides to set up a new department to focus on the foreign market. Philip Chin, who has number 129, will head the new department.
INSERT INTO department (dept_id, dept_name, dept_head_id) VALUES(600, ’Foreign Sales’, 129);

The final command creates the new entry for the new department. It appears as a new row at the bottom of the table in the Sales Manager’s window. 5 The Accountant, however, is not aware of the new department. At isolation level 2, the database server places locks to ensure that no row changes, but places no locks that stop other transactions from inserting new rows. The Accountant will only discover the new row if he should execute his select command again. In the Accountant’s window, execute the SELECT statement again. You will see the new row appended to the table.
SELECT * FROM department ORDER BY dept_id;

406

Chapter 14 Using Transactions and Isolation Levels

dept_id 100 200 300 400 500 600

dept_name R&D Sales Finance Marketing Shipping Foreign Sales

dept_head_id 501 902 1293 1576 703 129

The new row that appears is called a phantom row because, from the Accountant’s point of view, it appears like an apparition, seemingly from nowhere. The Accountant is connected at isolation level 2. At that level, the database server acquires locks only on the rows that he is using. Other rows are left untouched and hence there is nothing to prevent the Sales Manager from inserting a new row. 6 The Accountant would prefer to avoid such surprises in future, so he raises the isolation level of his current transaction to level 3. Enter the following commands for the Accountant.
SET TEMPORARY OPTION ISOLATION_LEVEL = 3 SELECT * FROM department ORDER BY dept_id

7

The Sales Manager would like to add a second department to handle sales initiative aimed at large corporate partners. Execute the following command in the Sales Manager’s window.
INSERT INTO department (dept_id, dept_name, dept_head_id) VALUES(700, ’Major Account Sales’, 902)

The Sales Manager’s window will pause during execution because the Accountant’s locks block the command. Click the Interrupt the SQL Statement button on the toolbar (or click Stop in the SQL menu) to interrupt this entry. 8 To avoid changing the demonstration database that comes with Adaptive Server Anywhere, you should roll back the insertion of the new departments. Execute the following command in the Sales Manager's window:
ROLLBACK

407

Isolation level tutorials
When the Accountant raised his isolation to level 3 and again selected all rows in the department table, the database server placed anti-insert locks on each row in the table, and one extra phantom lock to avoid insertion at the end of the table. When the Sales Manager attempted to insert a new row at the end of the table, it was this final lock that blocked her command. Notice that the Sales Manager’s command was blocked even though the Sales Manager is still connected at isolation level 2. The database server places anti-insert locks, like read locks, as demanded by the isolation level and statements of each transactions. Once placed, these locks must be respected by all other concurrent transactions.

$ For more information on locking, see "How locking works" on
page 413.

Tutorial 4 – Practical locking implications
The following continues the same scenario. In this tutorial, the Accountant and the Sales Manager both have tasks that involve the sales order and sales order items tables. The Accountant needs to verify the amounts of the commission checks paid to the sales employees for the sales they made during the month of April 1994. The Sales Manager notices that a few orders have not been added to the database and wants to add them. Their work demonstrates phantom locking. When a transaction at isolation level 3 selects rows which match a given criterion, the database server places anti-insert locks to stop other transactions from inserting rows which would also match. The number of locks placed on your behalf depends both on the search criterion and on the design of your database. If you have not done so, do steps 1 through 3 of the previous tutorial which describe how to start two copies of Interactive SQL. 1 Set the isolation level to 2 in both the Sales Manager window and the Accountant window by executing the following command.
SET TEMPORARY OPTION ISOLATION_LEVEL = 2

2

Each month, the sales representatives are paid a commission, which is calculated as a percentage of their sales for that month. The Accountant is preparing the commission checks for the month of April 1994. His first task is to calculate the total sales of each representative during this month. Enter the following command in the Accountant’s window. Prices, sales order information, and employee data are stored in separate tables. Join these tables using the foreign key relationships to combine the necessary pieces of information.

408

Chapter 14 Using Transactions and Isolation Levels
SELECT emp_id, emp_fname, emp_lname, SUM(sales_order_items.quantity * unit_price) AS "April sales" FROM employee KEY JOIN sales_order KEY JOIN sales_order_items KEY JOIN product WHERE ’1994-04-01’ <= order_date AND order_date < ’1994-05-01’ GROUP BY emp_id, emp_fname, emp_lname emp_id 129 195 299 467 667 690 856 902 949 1142 1596 emp_fname Philip Marc Rollin James Mary Kathleen Samuel Moira Pamela Alison Catherine emp_lname Chin Dill Overbey Klobucher Garcia Poitras Singer Kelly Savarino Clark Pickett April sales 2160.00 2568.00 5760.00 3228.00 2712.00 2124.00 5076.00 5460.00 2592.00 2184.00 1788.00

3

The Sales Manager notices that a big order sold by Philip Chin was not entered into the database. Philip likes to be paid his commission promptly, so the Sales manager enters the missing order, which was placed on April 25. In the Sales Manager’s window, enter the following commands. The Sales order and the items are entered in separate tables because one order can contain many items. You should create the entry for the sales order before you add items to it. To maintain referential integrity, the database server allows a transaction to add items to an order only if that order already exists.
INSERT into sales_order VALUES ( 2653, 174, ’1994-04-22’, ’r1’, ’Central’, 129); INSERT into sales_order_items VALUES ( 2653, 1, 601, 100, ’1994-04-25’ ); COMMIT;

409

Isolation level tutorials
4 The Accountant has no way of knowing that the Sales Manager has just added a new order. Had the new order been entered earlier, it would have been included in the calculation of Philip Chin’s April sales. In the Accountant’s window, calculate the April sales totals again. Use the same command, and observe that Philip Chin’s April sales changes to $4560.00.
emp_id 129 195 299 467 667 690 856 902 949 1142 1596 emp_fname Philip Marc Rollin James Mary Kathleen Samuel Moira Pamela Alison Catherine emp_lname Chin Dill Overbey Klobucher Garcia Poitras Singer Kelly Savarino Clark Pickett April sales 4560.00 2568.00 5760.00 3228.00 2712.00 2124.00 5076.00 5460.00 2592.00 2184.00 1788.00

Imagine that the Accountant now marks all orders placed in April to indicate that commission has been paid. The order that the Sales Manager just entered might be found in the second search and marked as paid, even though it was not included in Philip’s total April sales! 5 At isolation level 3, the database server places anti-insert locks to ensure that no other transactions can add a row which matches the criterion of a search or select. First, roll back the insertion of Philip’s missing order: Execute the following statement in the Sales Manager’s window.
ROLLBACK

6

In the Accountant’s window, execute the following two statements.
ROLLBACK; SET TEMPORARY OPTION ISOLATION_LEVEL = 3;

7

In the Sales Manager’s window, execute the following statements to remove the new order.

410

Chapter 14 Using Transactions and Isolation Levels
DELETE FROM sales_order_items WHERE id = 2653; DELETE FROM sales_order WHERE id = 2653; COMMIT;

8

In the Accountant’s window, execute same query as before.
SELECT emp_id, emp_fname, emp_lname, SUM(sales_order_items.quantity * unit_price) AS "April sales" FROM employee KEY JOIN sales_order KEY JOIN sales_order_items KEY JOIN product WHERE ’1994-04-01’ <= order_date AND order_date < ’1994-05-01’ GROUP BY emp_id, emp_fname, emp_lname

Because you set the isolation to level 3, the database server will automatically place anti-insert locks to ensure that the Sales Manager can’t insert April order items until the Accountant finishes his transaction. 9 Return to the Sales Manager’s window. Again attempt to enter Philip Chin’s missing order.
INSERT INTO sales_order VALUES ( 2653, 174, ’1994-04-22’, ’r1’,’Central’, 129)

The Sales Manager’s window will hang; the operation will not complete. Click the Interrupt the SQL Statement button on the toolbar (or click Stop in the SQL menu) to interrupt this entry. 10 The Sales Manager can’t enter the order in April, but you might think that she could still enter it in May. Change the date of the command to May 05 and try again.
INSERT INTO sales_order VALUES ( 2653, 174, ’1994-05-05’, ’r1’, ’Central’, 129)

The Sales Manager’s window will hang again. Click the Interrupt the SQL Statement button on the toolbar (or click Stop in the SQL menu) to interrupt this entry. Although the database server places no more locks than necessary to prevent insertions, these locks have the potential to interfere with a large number of other transactions.

411

Isolation level tutorials
The database server places locks in table indices. For example, it places a phantom lock in an index so a new row cannot be inserted immediately before it. However, when no suitable index is present, it must lock every row in the table. In some situations, anti-insert locks may block some insertions into a table, yet allow others. 11 The Sales Manager wishes to add a second item to order 2651. Use the following command.
INSERT INTO sales_order_items VALUES ( 2651, 2, 302, 4, ’1994-05-22’ )

All goes well, so the Sales Manager decides to add the following item to order 2652 as well.
INSERT INTO sales_order_items VALUES ( 2652, 2, 600, 12, ’1994-05-25’ )

The Sales Manager’s window will hang. Click the Interrupt the SQL Statement button on the toolbar (or click Stop in the SQL menu) to interrupt this entry. 12 Conclude this tutorial by undoing any changes to avoid changing the demonstration database. Enter the following command in the Sales Manager’s window.
ROLLBACK

Enter the same command in the Accountant’s window.
ROLLBACK

You may now close both windows.

412

Chapter 14 Using Transactions and Isolation Levels

How locking works
When the database server processes a transaction, it can lock one or more rows of a table. The locks maintain the reliability of information stored in the database by preventing concurrent access by other transactions. They also improve the accuracy of result queries by identifying information which is in the process of being updated. The database server places these locks automatically and needs no explicit instruction. It holds all the locks acquired by a transaction until the transaction is completed, for example by either a COMMIT or ROLLBACK statement, with a single exception noted in "Early release of read locks—an exception" on page 424. The transaction that has access to the row is said to hold the lock. Depending on the type of lock, other transactions may have limited access to the locked row, or none at all. You can use the sa_locks system procedure to list information about locks that are held in the database. For more information, see "sa_locks system procedure" on page 969 of the book ASA Reference.

Objects that can be locked
Adaptive Server Anywhere places locks on the following objects. ♦
Rows in tables A transaction can lock a particular row to prevent

another transaction from changing it. A transaction must place a write lock on a row if it intends to modify the row. ♦
Insertion points between rows Transactions typically scan rows using the ordering imposed by an index, or scan rows sequentially. In either case, a lock can be placed on the scan position. For example, placing a lock in an index can prevent another transaction from inserting a row with a specific value or range of values. Table schemas A transaction can lock the schema of a table,

preventing other transactions from modifying the table’s structure. Of these objects, rows are likely the most intuitive. It is understandable that a transaction reading, updating, deleting, or inserting a row should limit the simultaneous access to other transactions. Similarly, a transaction changing the structure of a table, perhaps inserting a new column, could greatly impact other transactions. In such a case, it is essential to limit the access of other transactions to prevent errors.

413

How locking works

Row orderings

You can use an index to order rows based on a particular criterion established when the index was constructed. When there is no index, Adaptive Server Anywhere orders rows by their physical placement on disk; in the case of a sequential scan, the specific ordering is defined by the internal workings of the database server. You should not rely on the order of rows in a sequential scan. From the point of view of scanning the rows, however, Adaptive Server Anywhere treats the request similarly to an indexed scan, albeit using an ordering of its own choosing. It can place locks on positions in the scan as it would were it using an index. Through locking a scan position, a transaction prevents some actions by other transactions relating to a particular range of values in that ordering of the rows. Insert and anti-insert locks are always placed on scan positions. For example, a transaction might delete a row, hence deleting a particular primary key value. Until this transaction either commits the change or rolls it back, it must protect its right to do either. In the case of a deleted row, it must ensure that no other transaction can insert a row using the same primary key value, hence making a rollback operation impossible. A lock on the scan position this row occupied reserves this right while having the least impact on other transactions.

The types of locks
Adaptive Server Anywhere uses four distinct types of locks to implement its locking scheme and ensure appropriate levels of isolation between transactions: ♦ ♦ ♦ ♦
read lock (shared) phantom lock or anti-insert lock (shared) write lock (exclusive) anti-phantom lock or insert lock (shared)

Each of these locks has a separate purpose, and they all work together. Each prevents a particular set of inconsistencies that could occur in their absence. Depending on the isolation level you select, the database server will use some or all of them to maintain the degree of consistency you require. The above types of locks have the following uses: ♦ A transaction acquires a write lock whenever it inserts, updates, or deletes a row. No other transaction can obtain either a read or a write lock on the same row when a write lock is set. A write lock is an exclusive lock.

414

Chapter 14 Using Transactions and Isolation Levels
♦ A transaction can acquire a read lock when it reads a row. Several transactions can acquire read locks on the same row (a read lock is a shared or nonexclusive lock). Once a row has been read locked, no other transaction can obtain a write lock on it. Thus, a transaction can ensure that no other transaction modifies or deletes a row by acquiring a read lock. An anti-insert lock, or phantom lock, is a shared lock placed on an indexed scan position to prevent phantom rows. It prevents other transactions from inserting a row into a table immediately before the row which is anti-insert locked. Anti-insert locks for lookups using indexes require a read lock on each row that is read, and one extra read lock to prevent insertions into the index at the end of the result set. Phantom rows for lookups that do not use indexes require a read lock on all rows in a table to prevent insertions from altering the result set, and so can have a bad effect on concurrency. An insert lock, or anti-phantom lock, is a shared lock placed on an indexed scan position to reserve the right to insert a row. Once one transaction acquires an insert lock on a row, no other transaction can acquire an anti-insert lock on the same row. A read lock on the corresponding row is always acquired at the same time as an insert lock to ensure that no other process can update or destroy the row, thereby bypassing the insert lock.

Adaptive Server Anywhere uses these four types of locks as necessary to ensure the level of consistency that you require. You do not need to explicitly request the use of a particular lock. Instead, you control the level of consistency, as is explained in the next section. Knowledge of the types of locks will guide you in choosing isolation levels and understanding the impact of each level on performance. Exclusive versus shared locks These four types of locks each fall into one of two categories: ♦
Exclusive locks Only one transaction can hold an exclusive lock on a

row of a table at one time. No transaction can obtain an exclusive lock while any other transaction holds a lock of any type on the same row. Once a transaction acquires an exclusive lock, requests to lock the row by other transactions will be denied. Write locks are exclusive. ♦
Shared locks Any number of transactions may acquire shared locks on

any one row at the same time. Shared locks are sometimes referred to as non-exclusive locks. Read locks, insert locks, and anti-insert locks are shared.

415

How locking works
Only one transaction should change any one row at one time. Otherwise, two simultaneous transactions might try to change one value to two different new ones. Hence, it is important that a write lock be exclusive. By contrast, no difficulty arises if more than one transaction wants to read a row. Since neither is changing it, there is no conflict of interest. Hence, read locks may be shared. You may apply similar reasoning to anti-insert and insert locks. Many transactions can prevent the insertion of a row in a particular scan position by each acquiring an anti-insert lock. Similar logic applies for insert locks. When a particular transaction requires exclusive access, it can easily achieve exclusive access by obtaining both an anti-insert and an insert lock on the same row. These locks to not conflict when they are held by the same transaction. Which specific locks conflict? The following table identifies the combination of locks that conflict.
read read write anti-insert insert conflict conflict write conflict conflict conflict anti-insert insert

These conflicts arise only when the locks are held by different transactions. For example, one transaction can obtain both anti-insert and insert locks on a single scan position to obtain exclusive access to a location.

Locking during queries
The locks that Adaptive Server Anywhere uses when a user enters a SELECT statement depend on the transaction’s isolation level. SELECT statements at isolation level 0 SELECT statements at isolation level 1 No locking operations are required when executing a SELECT statement at isolation level 0. Each transaction is not protected from changes introduced by other transactions. It is the responsibility of the programmer or database user to interpret the result of these queries with this limitation in mind. You may be surprised to learn that Adaptive Server Anywhere uses almost no more locks when running a transaction at isolation level 1 than it does at isolation level 0. Indeed, the database server modifies its operation in only two ways.

416

Chapter 14 Using Transactions and Isolation Levels
The first difference in operation has nothing to do with acquiring locks, but rather with respecting them. At isolation level 0, a transaction is free to read any row, whether or not another transaction has acquired a write lock on it. By contrast, before reading each row an isolation level 1 transaction must check whether a write lock is in place. It cannot read past any write-locked rows because doing so might entail reading dirty data. The second difference in operation creates cursor stability. Cursor stability is achieved by acquiring a read lock on the current row of a cursor. This read lock is released when the cursor is moved. More than one row may be affected if the contents of the cursor is the result of a join. In this case, the database server acquires read locks on all rows which have contributed information to the cursor’s current row and removes all these locks as soon as another row of the cursor is selected as current. A read lock placed to ensure cursor stability is the only type of lock that does not persist until the end of a transaction. SELECT statements at isolation level 2 At isolation level 2, Adaptive Server Anywhere modifies its procedures to ensure that your reads are repeatable. If your SELECT command returns values from every row in a table, then the database server acquires a read lock on each row of the table as it reads it. If, instead, your SELECT contains a WHERE clause, or another condition which restricts the rows to selected, then the database server instead reads each row, tests the values in the row against your criterion, and then acquires a read lock on the row if it meets your criterion. As at all isolation levels, the locks acquired at level 2 include all those set at levels 1 and 0. Thus, cursor stability is again ensured and dirty reads are not permitted. SELECT statements at isolation level 3 When operating at isolation level 3, Adaptive Server Anywhere is obligated to ensure that all schedules are serializable. In particular, in addition to the requirements imposed at each of the lower levels, it must eliminate phantom rows. To accommodate this requirement, the database server uses read locks and anti-insert locks. When you make a selection, the database server acquires a read lock on each row that contributes information to your result set. Doing so ensures that no other transactions can modify that material before you have finished using it.

417

How locking works
This requirement is similar to the procedures that the database server uses at isolation level 2, but differs in that a lock must be acquired for each row read, whether or not it meets any attached criteria. For example, if you select the names of all employees in the sales department, then the server must lock all the rows which contain information about a sales person, whether the transaction is executing at isolation level 2 or 3. At isolation level 3, however, it must also acquire read locks on each of the rows of employees which are not in the sales department. Otherwise, someone else accessing the database could potentially transfer another employee to the sales department while you were still using your results. The fact that a read lock must be acquired on each row whether or not it meets your criteria has two important implications. ♦ ♦ The database server may need to place many more locks than would be necessary at isolation level 2. The database server can operate a little more efficiently: It can immediately acquire a read lock on each row at as it reads it, since the locks must be placed whether or not the information in the row is accepted.

The number of anti-insert locks the server places can very greatly and depends upon your criteria and on the indexes available in the table. Suppose you select information about the employee with Employee ID 123. If the employee ID is the primary key of the employee table, then the database server can economize its operations. It can use the index, which is automatically built for a primary key, to locate the row efficiently. In addition, there is no danger that another transaction could change another Employee’s ID to 123 because primary key values must be unique. The server can guarantee that no second employee is assigned that ID number simply by acquiring a read lock on only the one row containing information about the employee with that number. By contrast, the database server would acquire more locks were you instead to select all the employees in the sales department. Since any number of employees could be added to the department, the server will likely have to read every row in the employee table and test whether each person is in sales. If this is the case, both read and anti-insert locks must be acquired for each row.

Locking during inserts
INSERT operations create new rows. Adaptive Server Anywhere employs the following procedure to ensure data integrity.

418

Chapter 14 Using Transactions and Isolation Levels
1 Make a location in memory to store the new row. The location is initially hidden from the rest of the database, so there is as yet no concern that another transaction could access it. Fill the new row with any supplied values. Write lock the new row. Place an insert lock in the table to which the row is being added. Recall that insert locks are exclusive, so once the-insert lock is acquired, no other transaction can block the insertion by acquiring an anti-insert lock Insert the row into the table. Other transactions can now, for the first time, see that the new row exists. They can’t modify or delete it, though, because of the write lock acquired earlier. Update all affected indexes and verify both referential integrity and uniqueness, where appropriate. Verifying referential integrity means ensuring that no foreign key points to a primary key that does not exist. Primary key values must be unique. Other columns may also be defined to contain only unique values, and if any such columns exist, uniqueness is verified. The transaction can be committed provided referential integrity will not be violated by doing so: record the operation in the transaction log file and release all locks. Insert other rows as required, if you have selected the cascade option, and fire triggers. For more information about how locks are used during inserts, see "Anti-insert locks" on page 421.

2 3 4

5

6

7

8

$
Uniqueness

You can ensure that all values in a particular column, or combination of columns, are unique. The database server always performs this task by building an index for the unique column, even if you do not explicitly create one. In particular, all primary key values must be unique. The database server automatically builds an index for the primary key of every table. Thus, you should not ask the database server to create an index on a primary key, as that index would be a redundant index.

Orphans and referential integrity

A foreign key is a reference to a primary key, usually in another table. When that primary key doesn’t exist, the offending foreign key is called an orphan. Adaptive Server Anywhere automatically ensures that your database contains no orphans. This process is referred to as verifying referential integrity. The database server verifies referential integrity by counting orphans.

419

How locking works

WAIT FOR COMMIT

You can ask the database server to delay verifying referential integrity to the end of your transaction. In this mode, you can insert one row which contains a foreign key, then insert a second row which contains the missing primary key. You must perform both operations in the same transaction. Otherwise, the database server will not allow your operations. To request that the database server delay referential integrity checks until commit time, set the value of the option WAIT_FOR_COMMIT to ON. By default, this option is OFF. To turn it on, issue the following command:
SET OPTION WAIT_FOR_COMMIT = ON;

Before committing a transaction, the database server verifies that referential integrity is maintained by checking the number of orphans your transaction has created. At the end of every transaction, that number must be zero. Even if the necessary primary key exists at the time you insert the row, the database server must ensure that it still exists when you commit your results. It does so by placing a read lock on the target row. With the read lock in place, any other transaction is still free to read that row, but none can delete or alter it.

Locking during updates
The database server modifies the information contained in a particular record using the following procedure. 1 2 Write lock the affected row. If any entries changed are included in an index, delete each index entry corresponding to the old values. Make a record of any orphans created by doing so. Update each of the affected values. If indexed values were changed, add new index entries. Verify uniqueness where appropriate and verify referential integrity if a primary of foreign key was changed. The transaction can be committed provided referential integrity will not be violated by doing so: record the operation in the transaction log file, including the previous values of all entries in the row, and release all locks. Cascade the insert or delete operations, if you have selected this option and primary or secondary keys are affected.

3 4

5

6

420

Chapter 14 Using Transactions and Isolation Levels
You may be surprised to see that the deceptively simple operation of changing a value in a table can necessitate a rather large number of operations. The amount of work that the database server needs to do is much less if the value you are changing is not part of a primary or foreign key. It is lower still if it is not contained in an index, either explicitly or implicitly because you have declared that attribute unique. The operation of verifying referential integrity during an UPDATE operation is no less simple than when the verification is performed during an INSERT. In fact, when you change the value of a primary key, you may create orphans. When you insert the replacement value, the database server must check for orphans once more.

Locking during deletes
The DELETE operation follows almost the same steps as the INSERT operation, except in the opposite order. 1 2 Write lock the affected row. Delete each index entry present for the any values in the row. Immediately prior to deleting each index entry, acquire one or more antiinsert locks as necessary to prevent another transaction inserting a similar entry before the delete is committed. In order to verify referential integrity, the database server also keeps track of any orphans created as a side effect of the deletion. Remove the row from the table so that it is no longer visible to other transactions. The row cannot be destroyed until the transaction is committed because doing so would remove the option of rolling back the transaction. The transaction can be committed provided referential integrity will not be violated by doing so: record the operation in the transaction log file including the values of all entries in the row, release all locks, and destroy the row. Cascade the delete operation, if you have selected this option and have modified a primary or foreign key.

3

4

5 Anti-insert locks

The database server must ensure that the DELETE operation can be rolled back. It does so in part by acquiring anti-insert locks. These locks are not exclusive; however, they deny other transactions the right to insert rows that make it impossible to roll back the DELETE operation. For example, the row deleted may have contained a primary key value, or another unique value. Were another transaction allowed to insert a row with the same value, the DELETE could not be undone without violating the uniqueness property. 421

How locking works
Adaptive Server Anywhere enforces uniqueness constraints through indexes. In the case of a simple table with only a one-attribute primary key, a single phantom lock may suffice. Other arrangements can quickly escalate the number of locks required. For example, the table may have no primary key or other index associated with any of the attributes. Since the rows in a table have no fundamental ordering, the only way of preventing inserts may be to anti-insert lock the entire table. Deleting a row can mean acquiring a great many locks. You can minimize the effect on concurrency in your database in a number of ways. As described earlier, indexes and primary keys reduce the number of locks required because they impose an ordering on the rows in the table. The database server automatically takes advantage of these orderings. Instead of acquiring locks on every row in the table, it can simply lock the next row. Without the index, the rows have no order and thus the concept of a next row is meaningless. The database server acquires anti-insert locks on the row following the row deleted. Should you delete the last row of a table, the database server simply places the anti-insert lock on an invisible end row. In fact, if the table contains no index, the number of anti-insert locks required is one more than the number of rows in the table. Anti-insert locks and read locks While one or more anti-insert locks exclude an insert lock and one or more read locks exclude a write lock, no interaction exists between antiinsert/insert locks and read/write locks. For example, although a write lock cannot be acquired on a row that contains a read lock, it can be acquired on a row that has only an anti-insert lock. More options are open to the database server because of this flexible arrangement, but it means that the server must generally take the extra precaution of acquiring a read lock when acquiring an anti-insert lock. Otherwise, another transaction could delete the row.

Two-phase locking
Often, the general information about locking provided in the earlier sections will suffice to meet your needs. There are times, however, when you may benefit from more knowledge of what goes on inside the database server when you perform basic types of operations. This knowledge will provide you with a better basis from which to understand and predict potential problems that users of your database may encounter. Two-phase locking is important in the context of ensuring that schedules are serializable. The two-phase locking protocol specifies a procedure each transaction follows.

422

Chapter 14 Using Transactions and Isolation Levels
This protocol is important because, if observed by all transactions, it will guarantee a serializable, and thus correct, schedule. It may also help you understand why some methods of locking permit some types of inconsistencies. The two-phase locking protocol 1 2 Before operating on any row, a transaction must acquire a lock on that row. After releasing a lock, a transaction must never acquire any more locks.

In practice, a transaction normally holds locks until it terminates with either a COMMIT or ROLLBACK statement. Releasing locks before the end of the transaction disallows the operation of rolling back the changes whenever doing so would necessitate operating on rows to return them to an earlier state. The two-phase locking protocol allows the statement of the following important theorem:
The two-phase locking theorem

If all transactions obey the two-phase locking protocol, then all possible interleaved schedules are serializable. In other words, if all transactions follow the two-phase locking protocol, then none of the inconsistencies mentioned above are possible. This protocol defines the operations necessary to ensure complete consistency of your data, but you may decide that some types of inconsistencies are permissible during some operations on your database. Eliminating all inconsistency often means reducing the efficiency of your database. Write locks are placed on modified, inserted, and deleted rows regardless of isolation level. They are always held until commit and rollback. Read locks at different isolation levels
Isolation level 0 1 Read locks None On rows that appear in the result set; they are held only when a cursor is positioned on a row. On rows that appear in the result set; they are held until the user executes a COMMIT or a ROLLBACK. On all rows read and all insertion points crossed in the computation of a result set

2

3

423

How locking works

$ For more information, see "Serializable schedules" on page 394
The details of locking are best broken into two sections: what happens during an INSERT, UPDATE, DELETE or SELECT and how the various isolation levels affect the placement of read, anti-insert, and insert locks. Although you can control the amount of locking that takes place within the database server by setting the isolation level, there is a good deal of locking that occurs at all levels, even at level 0. These locking operations are fundamental. For example, once one transaction updates a row, no other transaction can modify the same row before the first transaction completes. Without this precaution, you could not rollback the first transaction. The locking operations that the database server performs at isolation level 0 are the best to learn first exactly because they represent the foundation. The other levels add locking features, but do not remove any present in the lower levels. Thus, moving to higher isolation level adds operations not present at lower levels.

Early release of read locks—an exception
At isolation level 3, a transaction acquires a read lock on every row it reads. Ordinarily, a transaction never releases a lock before the end of the transaction. Indeed, it is essential that a transaction does not release locks early if the schedule is to be serializable. Adaptive Server Anywhere always retains write locks until a transaction completes. If it were to release a lock sooner, another transaction could modify that row making it impossible to roll back the first transaction. Read locks are released only in one, special circumstance. Under isolation level 1, transactions acquire a read lock on a row only when it becomes the current row of a cursor. Under isolation level 1, however, when that row is no longer current, the lock is released. This behavior is acceptable because the database server does not need to guarantee repeatable reads at isolation level 1.

$ For more information about isolation levels, see "Choosing isolation
levels" on page 394.

Special optimizations
The previous sections describe the locks acquired when all transactions are operating at a given isolation level. For example, when all transactions are running at isolation level 2, locking is performed as described in the appropriate section, above. 424

Chapter 14 Using Transactions and Isolation Levels
In practice, your database is likely to need to process multiple transactions that are at different levels. A few transactions, such as the transfer of money between accounts, must be serializable and so run at isolation level 3. For other operations, such as updating an address or calculating average daily sales, a lower isolation level will often suffice. While the database server is not processing any transactions at level 3, it optimizes some operations so as to improve performance. In particular, many extra anti-insert and insert locks are often necessary to support a level 3 transaction. Under some circumstances, the database server can avoid either placing or checking for some types of locks when no level 3 transactions are present. For example, the database server uses anti-insert locks to guard against two distinct types of circumstances: 1 2 Ensure that deletes in tables with unique attributes can be rolled back. Eliminate phantom rows in level 3 transactions.

If no level 3 transactions are using a particular table, then the database server need not place anti-insert locks in the index of a table that contains no unique attributes. If, however, even one level 3 transaction is present, all transactions, even those at level 0, must place anti-insert locks so that the level 3 transactions can identify their operations. Naturally, the database server always attaches notes to a table when it attempts the types of optimizations described above. Should a level 3 transaction suddenly start, you can be confident that the necessary locks will be put in place for it. You may have little control over the mix of isolation levels in use at one time as so much will depend on the particular operations that the various users of your database wish to perform. Where possible, however, you may wish to select the time that level 3 operations execute because they have the potential to cause significant slowing of database operations. The impact is magnified because the database server is forced to perform extra operations for lowerlevel operations.

425

Particular concurrency issues

Particular concurrency issues
This section discusses the following particular concurrency issues: ♦ ♦ "Primary key generation" on page 426 "Data definition statements and concurrency" on page 427

Primary key generation
You will encounter situations where the database should automatically generate a unique number. For example, if you are building a table to store sales invoices you might prefer that the database assign unique invoice numbers automatically, rather than require sales staff to pick them. There are many methods for generating such numbers. Example For example, invoice numbers could be obtained by adding 1 to the previous invoice number. This method will not work when there is more than one person adding invoices to the database. Two people may decide to use the same invoice number. There is more than one solution to the problem: ♦ Assign a range of invoice numbers to each person who adds new invoices. You could implement this scheme by creating a table with two columns user name and invoice number. The table would have one row for each user that adds invoices. Each time a user adds an invoice, the number in the table would be incremented and used for the new invoice. In order to handle all tables in the database, the table should have three columns: table name, user name, and last key value. You should periodically check that each person still has a sufficient supply of numbers. ♦ Create a table with two columns: table name and last key value. One row in this table would contain the last invoice number used. Each time someone adds an invoice, establish a new connection, increment the number in the table, and commit the change immediately. The incremented number can be used for the new invoice. Other users will be able to grab invoice numbers because you updated the row with a separate transaction that only lasted an instant. ♦ Probably the best solution is to use a column with a default value of AUTOINCREMENT. For example, 426

Chapter 14 Using Transactions and Isolation Levels
CREATE TABLE orders ( order_id INTEGER NOT NULL DEFAULT AUTOINCREMENT, order_date DATE, primary key( order_id ) )

On inserts into the table, if a value is not specified for the autoincrement column, a unique value is generated. If a value is specified, it will be used. If the value is larger than the current maximum value for the column, that value will be used as a starting point for subsequent inserts. The value of the most recently inserted row in an autoincrement column is available as the global variable @@identity.
Unique values in replicated databases

Different techniques are required if you replicate your database and more than one person can add entries which must later be merged. $ See "Replication and concurrency" on page 428.

Data definition statements and concurrency
Data definition statements that change an entire table, such as CREATE INDEX, ALTER TABLE, and TRUNCATE TABLE, are prevented whenever the statement table is currently being used by another connection. These data definition statements can be time consuming and the database server will not process requests referencing the same table while the command is being processed. The CREATE TABLE statement does not cause any concurrency conflicts. The GRANT statement, REVOKE statement, and SET OPTION statement also do not cause concurrency conflicts. These commands affect any new SQL statements sent to the database server, but do not affect existing outstanding statements. GRANT and REVOKE for a user are not allowed if that user is connected to the database.
Data definition statements and replicated databases

Using data definition statements in replicated databases requires special care. For more information see the separate manual entitled Data Replication with SQL Remote.

427

Replication and concurrency

Replication and concurrency
Some computers on your network might be portable computers that people take away from the office or which are occasionally connected to the network. There may be several database applications that they would like to use while not connected to the network. Database replication is the ideal solution to this problem. Using SQL Remote or MobiLink synchronization, you can publish information in a consolidated, or master, database to any number of other computers. You can control precisely the information replicated on any particular computer. Any person can receive particular tables, or even portions of the rows or columns of a table. By customizing the information each receives, you can ensure that their copy of the database is no larger than necessary to contain the information they require.

$ Extensive information on replication is provided in the separate manual
entitled Replication and Synchronization Guide. The information in this section is, thus, not intended to be complete. Rather, it introduces concepts related directly to locking and concurrency considerations. SQL Remote and MobiLink allow replicated databases to be updated from a central, consolidated database, as well as updating this same central data as the results of transactions processed on the remote machine. Since updates can occur in either direction, this ability is referred to as bi-directional replication. Since the results of transactions can affect the consolidated database, whether they are processed on the central machine or on a remote one, the effect is that of allowing concurrent transactions. Transactions may happen at the same time on different machines. They may even involve the same data. In this case, though, the machines may not be physically connected. No means may exist by which the remote machine can contact the consolidated database to set any form of lock or identify which rows have changed. Thus, locks can not prevent inconsistencies as they do when all transactions are processed by a single server. An added complication is introduced by the fact that any given remote machine may not hold a full copy of the database. Consider a transaction executed directly on the main, consolidated database. It may affect rows in two or more tables. The same transaction might not execute on a remote database, as there is no guarantee that one or both of the affected tables is replicated on that machine. Even if the same tables exist, they may not contain exactly the same information, depending upon how recently the information in the two databases has been synchronized.

428

Chapter 14 Using Transactions and Isolation Levels
To accommodate the above constraints, replication is not based on transactions, but rather on operations. An operation is a change to one row in a table. This change could be the result of an UPDATE, INSERT, or DELETE statement. An operation resulting from an UPDATE or DELETE identifies the initial values of each column and a transaction resulting from an INSERT or UPDATE records the final values. A transaction may result in none, one, or more than one operation. One operation will never result from two or more transactions. If two transactions modify a table, then two or more corresponding operations will result. If an operation results from a transaction processed on a remote computer, then it must be passed to the consolidated database so that the information can be merged. If, on the other hand, an operation results from a transaction on the consolidated computer, then the operation may need to be sent to some remote sites, but not others. Since each remote site may contain a replica of a portion of the complete database, SQL Remote knows to pass the operation to a remote site only when it affects that portion of the database. Transaction log based replication SQL Remote uses a transaction log based replication mechanism. When you activate SQL Remote on a machine, it scans the transaction log to identify the operations it must transfer and prepares one or more messages. SQL Remote can pass these messages between computers using a number of methods. It can create files containing the messages and store them in a designated directory. Alternatively, SQL Remote can pass messages using any of the most common messaging protocols. You likely can use your present e-mail system. Conflicts may arise when merging operations from remote sites into the consolidated database. For example, two people, each at a different remote site, may have changed the same value in the same table. Whereas the locking facility built into Adaptive Server Anywhere can eliminate conflict between concurrent transactions handled by the same server, it is impossible to automatically eliminate all conflicts between two remote users who both have permission to change the same value. As the database administrator, you can avoid this potential problem through suitable database design or by writing conflict resolution algorithms. For example, you can decide that only one person will be responsible for updating a particular range of values in a particular table. If such a restriction is impractical, then you can instead use the conflict resolution facilities of SQL Remote to implement triggers and procedures which resolve conflicts in a manner appropriate to the data involved.

$ SQL Remote provides the tools and programming facilities you need to
take full advantage of database replication. For further information, see the manual Replication and Synchronization Guide.

429

Summary

Summary
Transactions and locking are perhaps second only in importance to relations between tables. The integrity and performance of any database can benefit from the judicious use of locking and careful construction of transactions. Both are essential to creating databases that must execute a large number of commands concurrently. Transactions group SQL statements into logical units of work. You may end each by either rolling back any changes you have made or by committing these changes and so making them permanent. Transactions are essential to data recovery in the event of system failure. They also play a pivotal role in interweaving statements from concurrent transactions. To improve performance, multiple transactions must be executed concurrently. Each transaction is composed of component SQL statements. When two or more transactions are to be executed concurrently, the database server must schedule the execution of the individual statements. Concurrent transactions have the potential to introduce new, inconsistent results that could not arise were these same transactions executed sequentially. Many types of inconsistencies are possible, but four typical types are particularly important because they are mentioned in the ISO SQL/92 standard and the isolation levels are defined in terms of them. ♦ ♦ ♦ ♦
Dirty read

One transaction reads data modified, but not yet committed, A transaction reads the same row twice and gets

by another.
Non-repeatable read

different values.
Phantom row

A transaction selects rows, using a certain criterion, twice and finds new rows in the second result set.

Lost Update One transaction’s changes to a row are completely lost because another transaction is allowed to save an update based on earlier data.

A schedule is called serializable whenever the effect of executing the statements according to the schedule is the same as could be achieved by executing each of the transactions sequentially. Schedules are said to be correct if they are serializable. A serializable schedule will cause none of the above inconsistencies.

430

Chapter 14 Using Transactions and Isolation Levels
Locking controls the amount and types of interference permitted. Adaptive Server Anywhere provides you with four levels of locking: isolation levels 0, 1, 2, and 3. At the highest isolation, level 3, Adaptive Server Anywhere guarantees that the schedule is serializable, meaning that the effect of executing all the transactions is equivalent to running them sequentially. Unfortunately, locks acquired by one transaction may impede the progress of other transactions. Because of this problem, lower isolation levels are desirable whenever the inconsistencies they may allow are tolerable. Increased isolation to improve data consistency frequently means lowering the concurrency, the efficiency of the database at processing concurrent transactions. You must frequently balance the requirements for consistency against the need for performance to determine the best isolation level for each operation. Conflicting locking requirements between different transactions may lead to blocking or deadlock. Adaptive Server Anywhere contains mechanisms for dealing with both these situations, and provides you with options to control them. Transactions at higher isolation levels do not, however, always impact concurrency. Other transactions will be impeded only if they require access to locked rows. You can improve concurrency through careful design of your database and transactions. For example, you can shorten the time that locks are held by dividing one transaction into two shorter ones, or you might find that adding an index allows your transaction to operate at higher isolation levels with fewer locks. The increased popularity of portable computers will frequently mean that your database may need to be replicated. Replication is an extremely convenient feature of Adaptive Server Anywhere, but it introduces new considerations related to concurrency. These topics are covered in a separate manual.

431

Summary

432

P A R T

F O U R

Adding Logic to the Database

This part describes how to build logic into your database using SQL stored procedures, triggers, and Java. Storing logic in the database makes it available automatically to all applications, providing consistency, performance, and security benefits. The combined Java/Stored Procedure debugger is a powerful tool for debugging all kinds of logic.

433

434

C H A P T E R

1 5

Using Procedures, Triggers, and Batches

About this chapter

Procedures and triggers store procedural SQL statements in the database for use by all applications. They enhance the security, efficiency, and standardization of databases. User-defined functions are one kind of procedure that return a value to the calling environment for use in queries and other SQL statements. Batches are sets of SQL statements submitted to the database server as a group. Many features available in procedures and triggers, such as control statements, are also available in batches.

$ For many purposes, server-side JDBC provides a more flexible way to
build logic into the database than SQL stored procedures. For information on JDBC, see "Data Access Using JDBC" on page 591. Contents
Topic Procedure and trigger overview Benefits of procedures and triggers Introduction to procedures Introduction to user-defined functions Introduction to triggers Introduction to batches Control statements The structure of procedures and triggers Returning results from procedures Using cursors in procedures and triggers Errors and warnings in procedures and triggers Using the EXECUTE IMMEDIATE statement in procedures Transactions and savepoints in procedures and triggers Some tips for writing procedures Statements allowed in batches Calling external libraries from procedures Page 437 438 439 446 450 457 459 462 466 471 474 483 484 485 487 488

435

Procedure and trigger overview

436

Chapter 15 Using Procedures, Triggers, and Batches

Procedure and trigger overview
Procedures and triggers store procedural SQL statements in a database for use by all applications. They can include control statements that allow repetition (LOOP statement) and conditional execution (IF statement and CASE statement) of SQL statements. Procedures are invoked with a CALL statement, and use parameters to accept values and return values to the calling environment. Procedures can return result sets to the caller, call other procedures or fire triggers. For example, a user-defined function is a type of stored procedure that returns a single value to the calling environment. User-defined functions do not modify parameters passed to them, but rather, broaden the scope of functions available to queries and other SQL statements. Triggers are associated with specific database tables. They fire automatically whenever someone inserts, updates or deletes rows of the associated table. Triggers can call procedures and fire other triggers; however, they have no parameters, nor can they be invoked by a CALL statement. Procedure debugger You can debug stored procedures and triggers using the combined stored procedure/Java debugger. For more information, see "Debugging Logic in the Database" on page 621.

437

Benefits of procedures and triggers

Benefits of procedures and triggers
Definitions for procedures and triggers appear in the database, separately from any one database application. This separation provides a number of advantages. Standardization Procedures and triggers standardize actions performed by more than one application program. By coding the action once and storing it in the database for future use, applications need only call the procedure or fire the trigger to achieve the desired result repeatedly. And since changes occur in only one place, all applications using the action automatically acquire the new functionality if the implementation of the action changes. Procedures and triggers used in a network database server environment can access data in the database without requiring network communication. This means they execute faster and with less impact on network performance than if they had been implemented in an application on one of the client machines. When you create a procedure or trigger, it is automatically checked for correct syntax, and then stored in the system tables. The first time any application calls or fires a procedure or trigger, it is compiled from the system tables into the server’s virtual memory and executed from there. Since one copy of the procedure or trigger remains in memory after the first execution, repeated executions of the same procedure or trigger happen instantly. As well, several applications can use a procedure or trigger concurrently, or one application can use it recursively. Procedures are less efficient if they contain simple queries and have many arguments. For complex queries, procedures are more efficient. Security Procedures and triggers provide security by allowing users limited access to data in tables that they cannot directly examine or modify. Triggers, for example, execute under the table permissions of the owner of the associated table, but any user with permissions to insert, update or delete rows in the table can fire them. Similarly, procedures (including user-defined functions) execute with permissions of the procedure owner, but any user granted permissions can call them. This means that procedures and triggers can (and usually do) have different permissions than the user ID that invoked them.

Efficiency

438

Chapter 15 Using Procedures, Triggers, and Batches

Introduction to procedures
To use procedures, you need to understand how to: ♦ ♦ ♦ ♦ Create procedures Call procedures from a database application Drop or remove procedures Control who has permissions to use procedures

This section discusses the above aspects of using procedures, as well as some different applications of procedures.

Creating procedures
Adaptive Server Anywhere provides a number of tools that let you create a new procedure. In Sybase Central, you can use a wizard to provide necessary information and then complete the code in a generic code editor. Sybase Central also provides procedure templates (located in the Procedures & Functions folder) that you can open and modify. In Interactive SQL, you use the CREATE PROCEDURE statement to create procedures. However, you must have RESOURCE authority. Where you enter the statement depends on which tool you use.
v To create a new procedure (Sybase Central):

1 2 3 4 5 6

Connect to a database with DBA or Resource authority. Open the Procedures & Functions folder of the database. In the right pane, double-click Add Procedure/Function (Wizard). Follow the instructions in the wizard. When the Code Editor opens, complete the code of the procedure. To execute the code in the database, choose File®Save/Execute in Database. The new procedure appears in the Procedures & Functions folder.

v To create a new remote procedure (Sybase Central):

1

Connect to a database with DBA authority. 439

Introduction to procedures
2 3 4 5 Open the Procedures & Functions folder of the database. In the right pane, double-click Add Remote Procedure (Wizard). When the Code Editor opens, complete the code of the procedure. Follow the instructions in the wizard.
Tip

You can also create a remote procedure by right-clicking a remote server in the Remote Servers folder and choosing Add Remote Procedure from the popup menu.
v To create a procedure (SQL):

1 2

Launch Interactive SQL and connect to a database using DBA authority. Type the commands for the procedure in the SQL Statements pane of the Interactive SQL viewer.

v To create a procedure using a different tool:

Follow the instructions for your tool. You may need to change the command delimiter away from the semicolon before entering the CREATE PROCEDURE statement.

$ For more information about connecting, see "Connecting to a
Database" on page 33. Example The following simple example creates the procedure new_dept, which carries out an INSERT into the department table of the sample database, creating a new department.
CREATE PROCEDURE new_dept ( IN id INT, IN name CHAR(35), IN head_id INT ) BEGIN INSERT INTO dba.department ( dept_id, dept_name, dept_head_id ) VALUES ( id, name, head_id ); END

The body of a procedure is a compound statement. The compound statement starts with a BEGIN statement and concludes with an END statement. In the case of new_dept, the compound statement is a single INSERT bracketed by BEGIN and END statements. 440

Chapter 15 Using Procedures, Triggers, and Batches
Parameters to procedures are marked as one of IN, OUT, or INOUT. All parameters to the new_dept procedure are IN parameters, as they are not changed by the procedure.

$ For more information, see "CREATE PROCEDURE statement" on
page 453 of the book ASA Reference, "ALTER PROCEDURE statement" on page 389 of the book ASA Reference, and "Using compound statements" on page 460

Altering procedures
You can modify an existing procedure using either Sybase Central or Interactive SQL. You must have DBA authority or be the owner of the procedure. In Sybase Central, you cannot rename an existing procedure directly. Instead, you must create a new procedure with the new name, copy the previous code to it, and then delete the old procedure. In Interactive SQL, you can use an ALTER PROCEDURE statement to modify an existing procedure. You must include the entire new procedure in this statement (in the same syntax as in the CREATE PROCEDURE statement that created the procedure). You must also reassign user permissions on the procedure.

$ For information on altering database object properties, see "Setting
properties for database objects" on page 120.

$ For information on granting or revoking permissions for procedures,
see "Granting permissions on procedures" on page 747 and "Revoking user permissions" on page 750.
v To alter the code of a procedure (Sybase Central):

1 2 3

Open the Procedures & Functions folder. Right-click the desired procedure. From the popup menu, do one of the following: ♦ ♦ Choose Open as Watcom-SQL to edit the code in the Watcom-SQL dialect. Choose Open as Transact-SQL to edit the code in the Transact-SQL dialect.

4 5

In the Code Editor, edit the procedure’s code. To execute the code in the database, choose File®Save/Execute in Database. 441

Introduction to procedures
v To alter the code of a procedure (SQL):

1 2

Connect to the database. Execute an ALTER PROCEDURE statement. Include the entire new procedure in this statement.

$ For more information, see "ALTER PROCEDURE statement" on
page 389 of the book ASA Reference, "CREATE PROCEDURE statement" on page 453 of the book ASA Reference, and "Creating procedures" on page 439.

Calling procedures
CALL statements invoke procedures. Procedures can be called by an application program, or by other procedures and triggers.

$ For more information, see "CALL statement" on page 410 of the book
ASA Reference. The following statement calls the new_dept procedure to insert an Eastern Sales department:
CALL new_dept( 210, ’Eastern Sales’, 902 );

After this call, you may wish to check the department table to see that the new department has been added. All users who have been granted EXECUTE permissions for the procedure can call the new_dept procedure, even if they have no permissions on the department table.

$ For more information about EXECUTE permissions, see "EXECUTE
statement" on page 514 of the book ASA Reference.

Copying procedures in Sybase Central
In Sybase Central, you can copy procedures between databases. To do so, select the procedures in the right pane of Sybase Central and drag it to the Procedures & Functions folder of another connected database. A new procedure is then created, and the original procedure’s code is copied to it. Note that only the procedure code is copied to the new procedure. The other procedure properties (permissions, etc.) are not copied. A procedure can be copied to the same database, provided it is given a new name.

442

Chapter 15 Using Procedures, Triggers, and Batches

Deleting procedures
Once you create a procedure, it remains in the database until someone explicitly removes it. Only the owner of the procedure or a user with DBA authority can drop the procedure from the database.
v To delete a procedure (Sybase Central):

1 2 3

Connect to a database with DBA authority or as the owner of the procedure. Open the Procedures & Functions folder. Right-click the desired procedure and choose Delete from the popup menu.

v To delete a procedure (SQL):

1 2 Example

Connect to a database with DBA authority or as the owner of the procedure. Execute a DROP PROCEDURE statement.

The following statement removes the procedure new_dept from the database:
DROP PROCEDURE new_dept

Returning procedure results in parameters
Procedures return results to the calling environment in one of the following ways: ♦ ♦ ♦ Individual values are returned as OUT or INOUT parameters. Result sets can be returned. A single result can be returned using a RETURN statement.

This section describes how to return results from procedures as parameters. The following procedure on the sample database returns the average salary of employees as an OUT parameter.
CREATE PROCEDURE AverageSalary( OUT avgsal NUMERIC (20,3) ) BEGIN SELECT AVG( salary ) INTO avgsal FROM employee; END

443

Introduction to procedures
v To run this procedure and display its output (SQL):

1

Connect to the sample database from Interactive SQL with a user ID of DBA and a password of SQL. For more information about connecting, see "Connecting to a Database" on page 33. In the SQL Statements pane, type the above procedure code. Create a variable to hold the procedure output. In this case, the output variable is numeric, with three decimal places, so create a variable as follows:
CREATE VARIABLE Average NUMERIC(20,3)

2 3

4

Call the procedure using the created variable to hold the result:
CALL AverageSalary(Average)

If the procedure was created and run propertly, the Interactive SQL Messages pane does not display any errors. 5 Execute the SELECT Average statement to inspect the value of the variable. Look at the value of the output variable Average. The Interactive SQL Results pane displays the value 49988.623 for this variable, the average employee salary.

Returning procedure results in result sets
In addition to returning results to the calling environment in individual parameters, procedures can return information in result sets. A result set is typically the result of a query. The following procedure returns a result set containing the salary for each employee in a given department:
CREATE PROCEDURE SalaryList ( IN department_id INT) RESULT ( "Employee ID" INT, Salary NUMERIC(20,3) ) BEGIN SELECT emp_id, salary FROM employee WHERE employee.dept_id = department_id; END

If Interactive SQL calls this procedure, the names in the RESULT clause are matched to the results of the query and used as column headings in the displayed results. To test this procedure from Interactive SQL, you can CALL it, specifying one of the departments of the company. The results appear in the Interactive SQL Results pane.

444

Chapter 15 Using Procedures, Triggers, and Batches

Example

To list the salaries of employees in the R & D department (department ID 100), type the following:
CALL SalaryList (100) Employee ID 102 105 160 243 247 Salary 45700.000 62000.000 57490.000 72995.000 48023.690

Interactive SQL can only return multiple result sets if you have this option enabled on the Commands tab of the Options dialog. For more information, see "Returning multiple result sets from procedures" on page 469.

445

Introduction to user-defined functions

Introduction to user-defined functions
User-defined functions are a class of procedures that return a single value to the calling environment. This section introduces creating, using, and dropping user-defined functions

Creating user-defined functions
You use the CREATE FUNCTION statement to create user-defined functions. However, you must have RESOURCE authority. The following simple example creates a function that concatenates two strings, together with a space, to form a full name from a first name and a last name.
CREATE FUNCTION fullname (firstname CHAR(30), lastname CHAR(30)) RETURNS CHAR(61) BEGIN DECLARE name CHAR(61); SET name = firstname || ’ ’ || lastname; RETURN ( name ); END

v To create this example using Interactive SQL:

1

Connect to the sample database from Interactive SQL with a user ID of DBA and a password of SQL. For more information about connecting, see "Connecting to a Database" on page 33. In the SQL Statements pane, type the above function code.
Note

2

If you are using a tool other than Interactive SQL or Sybase Central, you may need to change the command delimiter away from the semicolon before entering the CREATE FUNCTION statement.

$ For more information, see "CREATE FUNCTION statement" on
page 445 of the book ASA Reference. The CREATE FUNCTION syntax differs slightly from that of the CREATE PROCEDURE statement. The following are distinctive differences: ♦ No IN, OUT, or INOUT keywords are required, as all parameters are IN parameters.

446

Chapter 15 Using Procedures, Triggers, and Batches
♦ ♦ The RETURNS clause is required to specify the data type being returned. The RETURN statement is required to specify the value being returned.

Calling user-defined functions
A user-defined function can be used, subject to permissions, in any place you would use a built-in non-aggregate function. The following statement in Interactive SQL returns a full name from two columns containing a first and last name:
SELECT fullname (emp_fname, emp_lname) FROM employee; Fullname (emp_fname, emp_lname) Fran Whitney Matthew Cobb Philip Chin ...

The following statement in Interactive SQL returns a full name from a supplied first and last name:
SELECT fullname (’Jane’, ’Smith’); Fullname (’Jane’,’Smith’) Jane Smith

Any user who has been granted EXECUTE permissions for the function can use the fullname function. Example The following user-defined function illustrates local declarations of variables. The customer table includes some Canadian customers sprinkled among those from the USA, but there is no country column. The user-defined function nationality uses the fact that the US zip code is numeric while the Canadian postal code begins with a letter to distinguish Canadian and US customers.
CREATE FUNCTION nationality( cust_id INT ) RETURNS CHAR( 20 ) BEGIN DECLARE natl CHAR(20);

447

Introduction to user-defined functions
IF cust_id IN ( SELECT id FROM customer WHERE LEFT(zip,1) > ’9’) THEN SET natl = ’CDN’; ELSE SET natl = ’USA’; END IF; RETURN ( natl ); END

This example declares a variable natl to hold the nationality string, uses a SET statement to set a value for the variable, and returns the value of the natl string to the calling environment. The following query lists all Canadian customers in the customer table:
SELECT * FROM customer WHERE nationality(id) = ’CDN’

Declarations of cursors and exceptions are discussed in later sections. The same query restated without the function would perform better, especially if an index on zip existed. For example,
Select * FROM customer WHERE zip > ’99999’

Notes

While this function is useful for illustration, it may perform very poorly if used in a SELECT involving many rows. For example, if you used the SELECT query on a table containing 100 000 rows, of which 10 000 are returned, the function will be called 10 000 times. If you use it in the WHERE clause of the same query, it would be called 100 000 times.

Dropping user-defined functions
Once you create a user-defined function, it remains in the database until someone explicitly removes it. Only the owner of the function or a user with DBA authority can drop a function from the database. The following statement removes the function fullname from the database:
DROP FUNCTION fullname

Permissions to execute user-defined functions
Ownership of a user-defined function belongs to the user who created it, and that user can execute it without permission. The owner of a user-defined function can grant permissions to other users with the GRANT EXECUTE command. 448

Chapter 15 Using Procedures, Triggers, and Batches
For example, the creator of the function fullname could allow another_user to use fullname with the statement:
GRANT EXECUTE ON fullname TO another_user

The following statement revokes permissions to use the function:
REVOKE EXECUTE ON fullname FROM another_user

$ For more information on managing user permissions on functions, see
"Granting permissions on procedures" on page 747.

449

Introduction to triggers

Introduction to triggers
You use triggers whenever referential integrity and other declarative constraints are insufficient.

$ For information on referential integrity, see "Ensuring Data Integrity"
on page 357 and "CREATE TABLE statement" on page 466 of the book ASA Reference. You may want to enforce a more complex form of referential integrity involving more detailed checking, or you may want to enforce checking on new data but allow legacy data to violate constraints. Another use for triggers is in logging the activity on database tables, independent of the applications using the database.
Trigger execution permissions

Triggers execute with the permissions of the owner of the associated table, not the user ID whose actions cause the trigger to fire. A trigger can modify rows in a table that a user could not modify directly. Triggers can be defined on one or more of the following triggering actions:
Action INSERT DELETE UPDATE UPDATE OF column-list Description Invokes the trigger whenever a new row is inserted into the table associated with the trigger Invokes the trigger whenever a row of the associated table is deleted. Invokes the trigger whenever a row of the associated table is updated. Invokes the trigger whenever a row of the associated table is updated such that a column in the column-list has been modified

Triggers can be either row-level or statement-level. Row-level triggers execute BEFORE or AFTER each row modified by the triggering insert, update, or delete operation changes. Statement-level triggers execute after the entire operation is performed. Flexibility in trigger execution time is particularly useful for triggers that rely on referential integrity actions such as cascaded updates or deletes being carried out (or not) as they execute.

450

Chapter 15 Using Procedures, Triggers, and Batches
If an error occurs while a trigger is executing, the operation that fired the trigger fails. INSERT, UPDATE, and DELETE are atomic operations (see "Atomic compound statements" on page 461). When they fail, all effects of the statement (including the effects of triggers and any procedures called by triggers) revert back to their pre-operation state.

Creating triggers
You create triggers using either Sybase Central or Interactive SQL. In Sybase Central, you can compose the code in a Code Editor. In Interactive SQL, you can use a CREATE TRIGGER statement. For both tools, you must have DBA or RESOURCE authority to create a trigger and you must have ALTER permissions on the table associated with the trigger. The body of a trigger consists of a compound statement: a set of semicolondelimited SQL statements bracketed by a BEGIN and an END statement. You cannot use COMMIT and ROLLBACK and some ROLLBACK TO SAVEPOINT statements within a trigger.

$ For more information, see the list of cross-references at the end of this
section.
v To create a new trigger for a given table (Sybase Central):

1 2 3 4 5

Open the Triggers folder of the desired table. In the right pane, double-click Add Trigger. Follow the instructions of the wizard. When the wizard finishes and opens the Code Editor for you, complete the code of the trigger. To execute the code in the database, choose File®Save/Execute in Database.

v To create a new trigger for a given table (SQL):

1 2 Example 1: A rowlevel INSERT trigger

Connect to a database. Execute a CREATE TRIGGER statement.

The following trigger is an example of a row-level INSERT trigger. It checks that the birthdate entered for a new employee is reasonable:
CREATE TRIGGER check_birth_date AFTER INSERT ON Employee REFERENCING NEW AS new_employee FOR EACH ROW

451

Introduction to triggers
BEGIN DECLARE err_user_error EXCEPTION FOR SQLSTATE ’99999’; IF new_employee.birth_date > ’June 6, 1994’ THEN SIGNAL err_user_error; END IF; END

This trigger fires after any row is inserted into the employee table. It detects and disallows any new rows that correspond to birth dates later than June 6, 1994. The phrase REFERENCING NEW AS new_employee allows statements in the trigger code to refer to the data in the new row using the alias new_employee. Signaling an error causes the triggering statement, as well as any previous effects of the trigger, to be undone. For an INSERT statement that adds many rows to the employee table, the
check_birth_date trigger fires once for each new row. If the trigger fails for

any of the rows, all effects of the INSERT statement roll back. You can specify that the trigger fires before the row is inserted rather than after by changing the first line of the example to:
CREATE TRIGGER mytrigger BEFORE INSERT ON Employee

The REFERENCING NEW clause refers to the inserted values of the row; it is independent of the timing (BEFORE or AFTER) of the trigger. You may find it easier in some cases to enforce constraints using declaration referential integrity or CHECK constraints, rather than triggers. For example, implementing the above example with a column check constraint proves more efficient and concise:
CHECK (@col <= ’June 6, 1994’)

Example 2: A rowlevel DELETE trigger example

The following CREATE TRIGGER statement defines a row-level DELETE trigger:
CREATE TRIGGER mytrigger BEFORE DELETE ON employee REFERENCING OLD AS oldtable FOR EACH ROW BEGIN ... END

The REFERENCING OLD clause enables the delete trigger code to refer to the values in the row being deleted using the alias oldtable. You can specify that the trigger fires after the row is deleted rather than before, by changing the first line of the example to: 452

Chapter 15 Using Procedures, Triggers, and Batches
CREATE TRIGGER check_birth_date AFTER DELETE ON employee

The REFERENCING OLD clause is independent of the timing (BEFORE or AFTER) of the trigger. Example 3: A statement-level UPDATE trigger example The following CREATE TRIGGER statement is appropriate for statementlevel UPDATE triggers:
CREATE TRIGGER mytrigger AFTER UPDATE ON employee REFERENCING NEW AS table_after_update OLD AS table_before_update FOR EACH STATEMENT BEGIN ... END

The REFERENCING NEW and REFERENCING OLD clause allows the UPDATE trigger code to refer to both the old and new values of the rows being updated. The table alias table_after_update refers to columns in the new row and the table alias table_before_update refers to columns in the old row. The REFERENCING NEW and REFERENCING OLD clause has a slightly different meaning for statement-level and row-level triggers. For statementlevel triggers the REFERENCING OLD or NEW aliases are table aliases, while in row-level triggers they refer to the row being altered.

$ For more information, see "CREATE TRIGGER statement" on
page 477 of the book ASA Reference, and "Using compound statements" on page 460.

Executing triggers
Triggers execute automatically whenever an INSERT, UPDATE, or DELETE operation is performed on the table named in the trigger. A rowlevel trigger fires once for each row affected, while a statement-level trigger fires once for the entire statement. When an INSERT, UPDATE, or DELETE fires a trigger, the order of operation is as follows: 1 2 3 4 BEFORE triggers fire. Referential actions are performed. The operation itself is performed. AFTER triggers fire.

453

Introduction to triggers
If any of the steps encounter an error not handled within a procedure or trigger, the preceding steps are undone, the subsequent steps are not performed, and the operation that fired the trigger fails.

Altering triggers
You can modify an existing trigger using either Sybase Central or Interactive SQL. You must be the owner of the table on which the trigger is defined, or be DBA, or have ALTER permissions on the table and have RESOURCE authority. In Sybase Central, you cannot rename an existing trigger directly. Instead, you must create a new trigger with the new name, copy the previous code to it, and then delete the old trigger. In Interactive SQL, you can use an ALTER TRIGGER statement to modify an existing trigger. You must include the entire new trigger in this statement (in the same syntax as in the CREATE TRIGGER statement that created the trigger).

$ For information on altering database object properties, see "Setting
properties for database objects" on page 120.
v To alter the code of a trigger (Sybase Central):

1 2 3

Open the Triggers folder of the desired table. Right-click the desired trigger. From the popup menu, do one of the following: ♦ ♦ Choose Open as Watcom SQL to edit the code in the Watcom SQL dialect. Choose Open as Transact SQL to edit the code in the Transact SQL dialect.

4 5

In the Code Editor, edit the trigger’s code. To execute the code in the database, choose File®Save/Execute in Database.

v To alter the code of a trigger (SQL):

1 2

Connect to the database. Execute an ALTER TRIGGER statement. Include the entire new trigger in this statement.

454

Chapter 15 Using Procedures, Triggers, and Batches

$ For more information, see "ALTER TRIGGER statement" on page 398
of the book ASA Reference.

Dropping triggers
Once you create a trigger, it remains in the database until someone explicitly removes it. You must have ALTER permissions on the table associated with the trigger to drop the trigger.
v To delete a trigger (Sybase Central):

1 2

Open the Triggers folder of the desired table. Right-click the desired trigger and choose Delete from the popup menu.

v To delete a trigger (Sybase Central):

1 2 Example

Connect to a database. Execute a DROP TRIGGER statement.

The following statement removes the trigger mytrigger from the database:
DROP TRIGGER mytrigger

$ For more information, see "DROP statement" on page 505 of the book
ASA Reference.

Trigger execution permissions
You cannot grant permissions to execute a trigger, since users cannot execute triggers: Adaptive Server Anywhere fires them in response to actions on the database. Nevertheless, a trigger does have permissions associated with it as it executes, defining its right to carry out certain actions. Triggers execute using the permissions of the owner of the table on which they are defined, not the permissions of the user who caused the trigger to fire, and not the permissions of the user who created the trigger. When a trigger refers to a table, it uses the group memberships of the table creator to locate tables with no explicit owner name specified. For example, if a trigger on user_1.Table_A references Table_B and does not specify the owner of Table_B, then either Table_B must have been created by user_1 or user_1 must be a member of a group (directly or indirectly) that is the owner of Table_B. If neither condition is met, a table not found message results when the trigger fires. 455

Introduction to triggers
Also, user_1 must have permissions to carry out the operations specified in the trigger.

456

Chapter 15 Using Procedures, Triggers, and Batches

Introduction to batches
A simple batch consists of a set of SQL statements, separated by semicolons or separated by a separate line with just the word go on it. The use of go is recommended. For example, the following set of statements form a batch, which creates an Eastern Sales department and transfers all sales reps from Massachusetts to that department.
INSERT INTO department ( dept_id, dept_name ) VALUES ( 220, ’Eastern Sales’ ) go UPDATE employee SET dept_id = 220 WHERE dept_id = 200 AND state = ’MA’ go COMMIT go

You can include this set of statements in an application and execute them together.
Interactive SQL and batches

Interactive SQL parses a list of semicolon-separated statements, such as the above, before sending them to the server. In this case, Interactive SQL sends each statement to the server individually, not as a batch. Unless you have such parsing code in your application, the statements would be sent and treated as a batch. Putting a BEGIN and END around a set of statements causes Interactive SQL to treat them as a batch. Many statements used in procedures and triggers can also be used in batches. You can use control statements (CASE, IF, LOOP, and so on), including compound statements (BEGIN and END), in batches. Compound statements can include declarations of variables, exceptions, temporary tables, or cursors inside the compound statement. The following batch creates a table only if a table of that name does not already exist:
IF NOT EXISTS ( SELECT * FROM SYSTABLE WHERE table_name = ’t1’ ) THEN CREATE TABLE t1 ( firstcol INT PRIMARY KEY, secondcol CHAR( 30 ) ) go

457

Introduction to batches
ELSE MESSAGE ’Table t1 already exists’ TO CLIENT; END IF

If you run this batch twice from Interactive SQL, it creates the table the first time you run it and displays the message in the Interactive SQL Messages window the next time you run it.

458

Chapter 15 Using Procedures, Triggers, and Batches

Control statements
There are a number of control statements for logical flow and decision making in the body of the procedure or trigger, or in a batch. Available control statements include:
Control statement Compound statements Syntax
BEGIN [ ATOMIC ] Statement-list END

$ For more information, see "BEGIN statement" on page 404 of the book ASA Reference.
Conditional execution: IF

$ For more information, see "IF statement" on page 545 of the book ASA Reference.
Conditional execution: CASE

IF condition THEN Statement-list ELSEIF condition THEN Statement-list ELSE Statement-list END IF CASE expression WHEN value THEN Statement-list WHEN value THEN Statement-list ELSE Statement-list END CASE WHILE condition LOOP Statement-list END LOOP

$ For more information, see "CASE statement" on page 412 of the book ASA Reference.

Repetition: WHILE, LOOP

$ For more information, see "LOOP statement" on page 567 of the book ASA Reference.
Repetition: FOR cursor loop

$ For more information, see "FOR statement" on page 528 of the book ASA Reference.
Break: LEAVE

FOR loop-name AS cursor-name CURSOR FOR select statement DO Statement-list END FOR LEAVE label

$ For more information, see "LEAVE statement" on page 558 of the book ASA Reference.
CALL
CALL procname( arg, ... )

$ For more information, see "CALL statement" on page 410 of
459

Control statements
Control statement the book ASA Reference. Syntax

$ For complete descriptions of each, see the entries in "SQL Statements"
on page 377 of the book ASA Reference

Using compound statements
A compound statement starts with the keyword BEGIN and concludes with the keyword END. The body of a procedure or trigger is a compound statement. Compound statements can also be used in batches. Compound statements can be nested, and combined with other control statements to define execution flow in procedures and triggers or in batches. A compound statement allows a set of SQL statements to be grouped together and treated as a unit. Delimit SQL statements within a compound statement with semicolons.

$ For more information about compound statements, see the "BEGIN
statement" on page 404 of the book ASA Reference.

Declarations in compound statements
Local declarations in a compound statement immediately follow the BEGIN keyword. These local declarations exist only within the compound statement. Within a compound statement you can declare: ♦ ♦ ♦ ♦ Variables Cursors Temporary tables Exceptions (error identifiers)

Local declarations can be referenced by any statement in that compound statement, or in any compound statement nested within it. Local declarations are not visible to other procedures called from the compound statement.

460

Chapter 15 Using Procedures, Triggers, and Batches

Atomic compound statements
An atomic statement is a statement executed completely or not at all. For example, an UPDATE statement that updates thousands of rows might encounter an error after updating many rows. If the statement does not complete, all changes revert back to their original state. The UPDATE statement is atomic. All noncompound SQL statements are atomic. You can make a compound statement atomic by adding the keyword ATOMIC after the BEGIN keyword.
BEGIN ATOMIC UPDATE employee SET manager_ID = 501 WHERE emp_ID = 467; UPDATE employee SET birth_date = ’bad_data’; END

In this example, the two update statements are part of an atomic compound statement. They must either succeed or fail as one. The first update statement would succeed. The second one causes a data conversion error since the value being assigned to the birth_date column cannot be converted to a date. The atomic compound statement fails and the effect of both UPDATE statements is undone. Even if the currently executing transaction is eventually committed, neither statement in the atomic compound statement takes effect. You cannot use COMMIT and ROLLBACK and some ROLLBACK TO SAVEPOINT statements within an atomic compound statement (see "Transactions and savepoints in procedures and triggers" on page 484). There is a case where some, but not all, of the statements within an atomic compound statement are executed. This happens when an exception handler within the compound statement deals with an error.

$ For more information, see "Using exception handlers in procedures and
triggers" on page 479.

461

The structure of procedures and triggers

The structure of procedures and triggers
The body of a procedure or trigger consists of a compound statement as discussed in "Using compound statements" on page 460. A compound statement consists of a BEGIN and an END, enclosing a set of SQL statements. Semicolons delimit each statement.

SQL statements allowed in procedures and triggers
You can use almost all SQL statements within procedures and triggers, including the following: ♦ ♦ ♦ ♦ ♦ ♦ SELECT, UPDATE, DELETE, INSERT and SET VARIABLE. The CALL statement to execute other procedures. Control statements (see "Control statements" on page 459). Cursor statements (see "Using cursors in procedures and triggers" on page 471). Exception handling statements (see "Using exception handlers in procedures and triggers" on page 479). The EXECUTE IMMEDIATE statement.

Some SQL statements you cannot use within procedures and triggers include: ♦ ♦ CONNECT statement DISCONNECT statement.

You can use COMMIT, ROLLBACK and SAVEPOINT statements within procedures and triggers with certain restrictions (see "Transactions and savepoints in procedures and triggers" on page 484).

$ For details, see the Usage for each SQL statement in the chapter "SQL
Statements" on page 377 of the book ASA Reference

462

Chapter 15 Using Procedures, Triggers, and Batches

Declaring parameters for procedures
Procedure parameters appear as a list in the CREATE PROCEDURE statement. Parameter names must conform to the rules for other database identifiers such as column names. They must have valid data types (see "SQL Data Types" on page 263 of the book ASA Reference), and must be prefixed with one of the keywords IN, OUT or INOUT. These keywords have the following meanings: ♦ ♦ ♦
IN

The argument is an expression that provides a value to the procedure.

OUT

The argument is a variable that could be given a value by the procedure. The argument is a variable that provides a value to the procedure, and could be given a new value by the procedure.

INOUT

You can assign default values to procedure parameters in the CREATE PROCEDURE statement. The default value must be a constant, which may be NULL. For example, the following procedure uses the NULL default for an IN parameter to avoid executing a query that would have no meaning:
CREATE PROCEDURE CustomerProducts( IN customer_id INTEGER DEFAULT NULL ) RESULT ( product_id INTEGER, quantity_ordered INTEGER ) BEGIN IF customer_id IS NULL THEN RETURN; ELSE SELECT product.id, sum( sales_order_items.quantity ) FROM product, sales_order_items, sales_order WHERE sales_order.cust_id = customer_id AND sales_order.id = sales_order_items.id AND sales_order_items.prod_id = product.id GROUP BY product.id; END IF; END

The following statement assigns the DEFAULT NULL, and the procedure RETURNs instead of executing the query.
CALL customerproducts();

463

The structure of procedures and triggers

Passing parameters to procedures
You can take advantage of default values of stored procedure parameters with either of two forms of the CALL statement. If the optional parameters are at the end of the argument list in the CREATE PROCEDURE statement, they may be omitted from the CALL statement. As an example, consider a procedure with three INOUT parameters:
CREATE PROCEDURE SampleProc( INOUT var1 INT DEFAULT 1, INOUT var2 int DEFAULT 2, INOUT var3 int DEFAULT 3 ) ...

We assume that the calling environment has set up three variables to hold the values passed to the procedure:
CREATE VARIABLE V1 INT; CREATE VARIABLE V2 INT; CREATE VARIABLE V3 INT;

The procedure SampleProc may be called supplying only the first parameter as follows:
CALL SampleProc( V1 )

in which case the default values are used for var2 and var3. A more flexible method of calling procedures with optional arguments is to pass the parameters by name. The SampleProc procedure may be called as follows:
CALL SampleProc( var1 = V1, var3 = V3 )

or as follows:
CALL SampleProc( var3 = V3, var1 = V1 )

Passing parameters to functions
User-defined functions are not invoked with the CALL statement, but are used in the same manner that built-in functions are. For example, the following statement uses the fullname function defined in "Creating userdefined functions" on page 446 to retrieve the names of employees:
v To list the names of all employees:

Type the following:
SELECT fullname(emp_fname, emp_lname) AS Name FROM employee

464

Chapter 15 Using Procedures, Triggers, and Batches

Name Fran Whitney Matthew Cobb Philip Chin Julie Jordan Robert Breault ...

Notes

♦ ♦

Default parameters can be used in calling functions. However, parameters cannot be passed to functions by name. Parameters are passed by value, not by reference. Even if the function changes the value of the parameter, this change is not returned to the calling environment. Output parameters cannot be used in user-defined functions. User-defined functions cannot return result sets.

♦ ♦

465

Returning results from procedures

Returning results from procedures
Procedures can return results in the form of a single row of data, or multiple rows. Results consisting of a single row of data can be passed back as arguments to the procedure. Results consisting of multiple rows of data are passed back as result sets. Procedures can also return a single value given in the RETURN statement.

$ For simple examples of how to return results from procedures, see
"Introduction to procedures" on page 439. For more detailed information, see the following sections.

Returning a value using the RETURN statement
The RETURN statement returns a single integer value to the calling environment, causing an immediate exit from the procedure. The RETURN statement takes the form:
RETURN expression

The value of the supplied expression is returned to the calling environment. To save the return value in a variable, use an extension of the CALL statement:
CREATE VARIABLE returnval INTEGER ; returnval = CALL myproc() ;

Returning results as procedure parameters
Procedures can return results to the calling environment in the parameters to the procedure. Within a procedure, parameters and variables can be assigned values using: ♦ ♦ Using the SET statement the SET statement. a SELECT statement with an INTO clause.

The following somewhat artificial procedure returns a value in an OUT parameter assigned using a SET statement:
CREATE PROCEDURE greater ( IN a INT, IN b INT, OUT c INT)

BEGIN IF a > b THEN SET c = a;

466

Chapter 15 Using Procedures, Triggers, and Batches
ELSE SET c = b; END IF ; END

Using single-row SELECT statements

Single-row queries retrieve at most one row from the database. This type of query uses a SELECT statement with an INTO clause. The INTO clause follows the select list and precedes the FROM clause. It contains a list of variables to receive the value for each select list item. There must be the same number of variables as there are select list items. When a SELECT statement executes, the server retrieves the results of the SELECT statement and places the results in the variables. If the query results contain more than one row, the server returns an error. For queries returning more than one row, you must use cursors. For information about returning more than one row from a procedure, see "Returning result sets from procedures" on page 468. If the query results in no rows being selected, a row not found warning appears. The following procedure returns the results of a single-row SELECT statement in the procedure parameters.
v To return the number of orders placed by a given customer:

Type the following:
CREATE PROCEDURE OrderCount (IN customer_ID INT, OUT Orders INT) BEGIN SELECT COUNT(dba.sales_order.id) INTO Orders FROM dba.customer KEY LEFT OUTER JOIN "dba".sales_order WHERE dba.customer.id = customer_ID; END

You can test this procedure in Interactive SQL using the following statements, which show the number of orders placed by the customer with ID 102:
CREATE VARIABLE orders INT; CALL OrderCount ( 102, orders ); SELECT orders;

Notes

♦ ♦

The customer_ID parameter is declared as an IN parameter. This parameter holds the customer ID passed in to the procedure. The Orders parameter is declared as an OUT parameter. It holds the value of the orders variable that returned to the calling environment.

467

Returning results from procedures
♦ ♦ No DECLARE statement is necessary for the Orders variable, as it is declared in the procedure argument list. The SELECT statement returns a single row and places it into the variable Orders.

Returning result sets from procedures
Result sets allow a procedure to return more than one row of results to the calling environment. The following procedure returns a list of customers who have placed orders, together with the total value of the orders placed. The procedure does not list customers who have not placed orders.
CREATE PROCEDURE ListCustomerValue () RESULT ("Company" CHAR(36), "Value" INT) BEGIN SELECT company_name, CAST( sum( sales_order_items.quantity * product.unit_price) AS INTEGER ) AS value FROM customer INNER JOIN sales_order INNER JOIN sales_order_items INNER JOIN product GROUP BY company_name ORDER BY value DESC; END

Type the following:
CALL ListCustomerValue ()

Company Chadwicks Overland Army Navy Martins Landing Sterling & Co. Carmel Industries ...

Value 8076 8064 6888 6804 6780 ...

Notes

The number of variables in the RESULT list must match the number of the SELECT list items. Automatic data type conversion is carried out where possible if data types do not match.

468

Chapter 15 Using Procedures, Triggers, and Batches
♦ ♦ ♦ The RESULT clause is part of the CREATE PROCEDURE statement, and does not have a command delimiter. The names of the SELECT list items do not need to match those of the RESULT list. When testing this procedure, Interactive SQL displays only the first result set by default. You can configure Interactive SQL to display more than one result set by setting the Show multiple result sets option on the Commands tab of the Options dialog. You can modify procedure result sets, unless they are generated from a view. The user calling the procedure requires the appropriate permissions on the underlying table to modify procedure results. This is different than the usual permissions for procedure execution, where the procedure owner must have permissions on the table.

Returning multiple result sets from procedures
Before Interactive SQL can return multiple result sets, you need to enable this option on the Commands tab of the Options dialog. By default, this option is disabled. If you change the setting, it takes effect in newly created connections (such as new windows).
v To enable multiple result set functionality:

1 2 3

Choose Tools®Options. In the resulting Options dialog, click the Commands tab. Select the Show Multiple Result Sets check box.

After you enable this option, a procedure can return more than one result set to the calling environment. If a RESULT clause is employed, the result sets must be compatible: they must have the same number of items in the SELECT lists, and the data types must all be of types that can be automatically converted to the data types listed in the RESULT list. The following procedure lists the names of all employees, customers, and contacts listed in the database:
CREATE PROCEDURE ListPeople() RESULT ( lname CHAR(36), fname CHAR(36) ) BEGIN SELECT emp_lname, emp_fname FROM employee; SELECT lname, fname FROM customer; SELECT last_name, first_name FROM contact;

469

Returning results from procedures
END

Notes

To test this procedure in Interactive SQL, enter the following statement in the SQL Statements pane:
CALL ListPeople ()

Returning variable result sets from procedures
The RESULT clause is optional in procedures. Omitting the result clause allows you to write procedures that return different result sets, with different numbers or types of columns, depending on how they are executed. If you do not use the variable result sets feature, you should use a RESULT clause for performance reasons. For example, the following procedure returns two columns if the input variable is Y, but only one column otherwise:
CREATE PROCEDURE names( IN formal char(1)) BEGIN IF formal = ’y’ THEN SELECT emp_lname, emp_fname FROM employee ELSE SELECT emp_fname FROM employee END IF END

The use of variable result sets in procedures is subject to some limitations, depending on the interface used by the client application. ♦
Embedded SQL You must DESCRIBE the procedure call after the cursor for the result set is opened, but before any rows are returned, in order to get the proper shape of result set.

$ For information about the DESCRIBE statement, see "DESCRIBE
statement" on page 500 of the book ASA Reference. ♦
ODBC

Variable result set procedures can be used by ODBC applications. The Adaptive Server Anywhere ODBC driver carries out the proper description of the variable result sets.

Open Client applications Open Client applications can use variable result set procedures. Adaptive Server Anywhere carries out the proper description of the variable result sets.

470

Chapter 15 Using Procedures, Triggers, and Batches

Using cursors in procedures and triggers
Cursors retrieve rows one at a time from a query or stored procedure with multiple rows in its result set. A cursor is a handle or an identifier for the query or procedure, and for a current position within the result set.

Cursor management overview
Managing a cursor is similar to managing a file in a programming language. The following steps manage cursors: 1 2 3 4 5 Declare a cursor for a particular SELECT statement or procedure using the DECLARE statement. Open the cursor using the OPEN statement. Use the FETCH statement to retrieve results one row at a time from the cursor. The warning Row Not Found signals the end of the result set. Close the cursor using the CLOSE statement.

By default, cursors are automatically closed at the end of a transaction (on COMMIT or ROLLBACK statements). Cursors are opened using the WITH HOLD clause will stay open for subsequent transactions until someone explicitly closes them.

$ For more information on positioning cursors, see "Cursor positioning"
on page 275.

Using cursors on SELECT statements in procedures
The following procedure uses a cursor on a SELECT statement. Based on the same query used in the ListCustomerValue procedure described in "Returning result sets from procedures" on page 468, it illustrates several features of the stored procedure language.
CREATE PROCEDURE TopCustomerValue ( OUT TopCompany CHAR(36), OUT TopValue INT ) BEGIN -- 1. Declare the "error not found" exception DECLARE err_notfound EXCEPTION FOR SQLSTATE ’02000’; -- 2. Declare variables to hold -each company name and its value

471

Using cursors in procedures and triggers
DECLARE ThisName CHAR(36); DECLARE ThisValue INT; -- 3. Declare the cursor ThisCompany -for the query DECLARE ThisCompany CURSOR FOR SELECT company_name, CAST( sum( sales_order_items.quantity * product.unit_price ) AS INTEGER ) AS value FROM customer INNER JOIN sales_order INNER JOIN sales_order_items INNER JOIN product GROUP BY company_name; -- 4. Initialize the values of TopValue SET TopValue = 0; -- 5. Open the cursor OPEN ThisCompany; -- 6. Loop over the rows of the query CompanyLoop: LOOP FETCH NEXT ThisCompany INTO ThisName, ThisValue; IF SQLSTATE = err_notfound THEN LEAVE CompanyLoop; END IF; IF ThisValue > TopValue THEN SET TopCompany = ThisName; SET TopValue = ThisValue; END IF; END LOOP CompanyLoop; -- 7. Close the cursor CLOSE ThisCompany; END

Notes

The TopCustomerValue procedure has the following notable features: ♦ The "error not found" exception is declared. This exception signals, later in the procedure, when a loop over the results of a query completes.

$ For more information about exceptions, see "Errors and warnings
in procedures and triggers" on page 474. ♦ ♦ Two local variables ThisName and ThisValue are declared to hold the results from each row of the query. The cursor ThisCompany is declared. The SELECT statement produces a list of company names and the total value of the orders placed by that company. The value of TopValue is set to an initial value of 0, for later use in the loop.

472

Chapter 15 Using Procedures, Triggers, and Batches
♦ ♦ The ThisCompany cursor opens. The LOOP statement loops over each row of the query, placing each company name in turn into the variables ThisName and ThisValue. If ThisValue is greater than the current top value, TopCompany and TopValue are reset to ThisName and ThisValue. The cursor closes at the end of the procedure. You can also write this procedure without a loop by adding an ORDER BY value DESC clause to the SELECT statement. Then, only the first row of the cursor needs to be fetched.

♦ ♦

The LOOP construct in the TopCompanyValue procedure is a standard form, exiting after the last row processes. You can rewrite this procedure in a more compact form using a FOR loop. The FOR statement combines several aspects of the above procedure into a single statement.
CREATE PROCEDURE TopCustomerValue2( OUT TopCompany CHAR(36), OUT TopValue INT ) BEGIN -- Initialize the TopValue variable SET TopValue = 0; -- Do the For Loop FOR CompanyFor AS ThisCompany CURSOR FOR SELECT company_name AS ThisName , CAST( sum( sales_order_items.quantity * product.unit_price ) AS INTEGER ) AS ThisValue FROM customer INNER JOIN sales_order INNER JOIN sales_order_items INNER JOIN product GROUP BY ThisName DO IF ThisValue > TopValue THEN SET TopCompany = ThisName; SET TopValue = ThisValue; END IF; END FOR; END

473

Errors and warnings in procedures and triggers

Errors and warnings in procedures and triggers
After an application program executes a SQL statement, it can examine a status code. This status code (or return code) indicates whether the statement executed successfully or failed and gives the reason for the failure. You can use the same mechanism to indicate the success or failure of a CALL statement to a procedure. Error reporting uses either the SQLCODE or SQLSTATE status descriptions. For full descriptions of SQLCODE and SQLSTATE error and warning values and their meanings, see "Database Error Messages" on page 649 of the book ASA Reference. Whenever a SQL statement executes, a value appears in special procedure variables called SQLSTATE and SQLCODE. That value indicates whether or not there were any unusual conditions encountered while the statement was being performed. You can check the value of SQLSTATE or SQLCODE in an IF statement following a SQL statement, and take actions depending on whether the statement succeeded or failed. For example, the SQLSTATE variable can be used to indicate if a row is successfully fetched. The TopCustomerValue procedure presented in section "Using cursors on SELECT statements in procedures" on page 471 used the SQLSTATE test to detect that all rows of a SELECT statement had been processed.

Default error handling in procedures and triggers
This section describes how Adaptive Server Anywhere handles errors that occur during a procedure execution, if you have no error handling built in to the procedure.

$ If you want to have a different behavior, you can use exception
handlers, described in "Using exception handlers in procedures and triggers" on page 479. Warnings are handled in a slightly different manner from errors: for a description, see "Default handling of warnings in procedures and triggers" on page 478. There are two ways of handling errors without using explicit error handling: ♦ ♦
Default error handling

The procedure or trigger fails and returns an error code to the calling environment.

ON EXCEPTION RESUME

If the ON EXCEPTION RESUME clause appears in the CREATE PROCEDURE statement, the procedure carries on executing after an error, resuming at the statement following the one causing the error.

474

Chapter 15 Using Procedures, Triggers, and Batches

$ The precise behavior for procedures that use ON EXCEPTION RESUME is dictated by the ON_TSQL_ERROR option setting. For more information, see "ON_TSQL_ERROR option" on page 202 of the book ASA Reference.
Default error handling Generally, if a SQL statement in a procedure or trigger fails, the procedure or trigger terminates execution and control returns to the application program with an appropriate setting for the SQLSTATE and SQLCODE values. This is true even if the error occurred in a procedure or trigger invoked directly or indirectly from the first one. In the case of a trigger, the operation causing the trigger is also undone and the error is returned to the application. The following demonstration procedures show what happens when an application calls the procedure OuterProc, and OuterProc in turn calls the procedure InnerProc, which then encounters an error.
CREATE PROCEDURE OuterProc() BEGIN MESSAGE ’Hello from OuterProc.’ TO CLIENT; CALL InnerProc(); MESSAGE ’SQLSTATE set to ’, SQLSTATE,’ in OuterProc.’ TO CLIENT END CREATE PROCEDURE InnerProc() BEGIN DECLARE column_not_found EXCEPTION FOR SQLSTATE ’52003’; MESSAGE ’Hello from InnerProc.’ TO CLIENT; SIGNAL column_not_found; MESSAGE ’SQLSTATE set to ’, SQLSTATE, ’ in InnerProc.’ TO CLIENT; END

Notes

The DECLARE statement in InnerProc declares a symbolic name for one of the predefined SQLSTATE values associated with error conditions already known to the server. The MESSAGE statement sends a message to the Interactive SQL Messages window. The SIGNAL statement generates an error condition from within the
InnerProc procedure.

♦ ♦

The following statement executes the OuterProc procedure:
CALL OuterProc();

The Interactive SQL Messages window displays the following:
Hello from OuterProc. Hello from InnerProc.

475

Errors and warnings in procedures and triggers
None of the statements following the SIGNAL statement in InnerProc execute: InnerProc immediately passes control back to the calling environment, which in this case is the procedure OuterProc. None of the statements following the CALL statement in OuterProc execute. The error condition returns to the calling environment to be handled there. For example, Interactive SQL handles the error by displaying a message window describing the error. The TRACEBACK function provides a list of the statements that were executing when the error occurred. You can use the TRACEBACK function from Interactive SQL by typing the following statement:
SELECT TRACEBACK(*)

Error handling with ON EXCEPTION RESUME
If the ON EXCEPTION RESUME clause appears in the CREATE PROCEDURE statement, the procedure checks the following statement when an error occurs. If the statement handles the error, then the procedure continues executing, resuming at the statement after the one causing the error. It does not return control to the calling environment when an error occurred.

$ The behavior for procedures that use ON EXCEPTION RESUME can be modified by the ON_TSQL_ERROR option setting. For more information, see "ON_TSQL_ERROR option" on page 202 of the book ASA Reference.
Error-handling statements include the following: ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ 476 IF SELECT @variable = CASE LOOP LEAVE CONTINUE CALL EXECUTE SIGNAL RESIGNAL DECLARE

Chapter 15 Using Procedures, Triggers, and Batches
♦ SET VARIABLE

The following example illustrates how this works. Drop the procedures Remember to drop both the InnerProc and OuterProc procedures by entering the following commands in the command window before continuing with the tutorial:
DROP PROCEDURE OuterProc; DROP PROCEDURE InnerProc

The following demonstration procedures show what happens when an application calls the procedure OuterProc; and OuterProc in turn calls the procedure InnerProc, which then encounters an error. These demonstration procedures are based on those used earlier in this section:
CREATE PROCEDURE OuterProc() ON EXCEPTION RESUME BEGIN DECLARE res CHAR(5); MESSAGE ’Hello from OuterProc.’ TO CLIENT; CALL InnerProc(); SELECT @res=SQLSTATE; IF res=’52003’ THEN MESSAGE ’SQLSTATE set to ’, res, ’ in OuterProc.’ TO CLIENT; END IF END; CREATE PROCEDURE InnerProc() ON EXCEPTION RESUME BEGIN DECLARE column_not_found EXCEPTION FOR SQLSTATE ’52003’; MESSAGE ’Hello from InnerProc.’ TO CLIENT; SIGNAL column_not_found; MESSAGE ’SQLSTATE set to ’, SQLSTATE, ’ in InnerProc.’ TO CLIENT; END

The following statement executes the OuterProc procedure:
CALL OuterProc();

The Interactive SQL Messages window then displays the following:
Hello from OuterProc. Hello from InnerProc. SQLSTATE set to 52003 in OuterProc.

The execution path is as follows: 1 OuterProc executes and calls InnerProc 477

Errors and warnings in procedures and triggers
2 3 4 In InnerProc, the SIGNAL statement signals an error. The MESSAGE statement is not an error-handling statement, so control is passed back to OuterProc and the message is not displayed. In OuterProc, the statement following the error assigns the SQLSTATE value to the variable named res. This is an error-handling statement, and so execution continues and the OuterProc message is displayed.

Default handling of warnings in procedures and triggers
Errors and warnings are handled differently. While the default action for errors is to set a value for the SQLSTATE and SQLCODE variables, and return control to the calling environment in the event of an error, the default action for warnings is to set the SQLSTATE and SQLCODE values and continue execution of the procedure. Drop the procedures Remember to drop both the InnerProc and OuterProc procedures by entering the following commands in the command window before continuing with the tutorial:
DROP PROCEDURE OuterProc; DROP PROCEDURE InnerProc

The following demonstration procedures illustrate default handling of warnings. These demonstration procedures are based on those used in "Default error handling in procedures and triggers" on page 474. In this case, the SIGNAL statement generates a row not found condition, which is a warning rather than an error.
CREATE PROCEDURE OuterProc() BEGIN MESSAGE ’Hello from OuterProc.’ TO CLIENT; CALL InnerProc(); MESSAGE ’SQLSTATE set to ’, SQLSTATE,’ in OuterProc.’ TO CLIENT; END CREATE PROCEDURE InnerProc() BEGIN DECLARE row_not_found EXCEPTION FOR SQLSTATE ’02000’; MESSAGE ’Hello from InnerProc.’ TO CLIENT; SIGNAL row_not_found; MESSAGE ’SQLSTATE set to ’, SQLSTATE, ’ in InnerProc.’ TO CLIENT; END

The following statement executes the OuterProc procedure:
CALL OuterProc();

478

Chapter 15 Using Procedures, Triggers, and Batches
The Interactive SQL Messages window then displays the following:
Hello from OuterProc. Hello from InnerProc. SQLSTATE set to 02000 in InnerProc. SQLSTATE set to 00000 in OuterProc.

The procedures both continued executing after the warning was generated, with SQLSTATE set by the warning (02000). Execution of the second MESSAGE statement in InnerProc resets the warning. Successful execution of any SQL statement resets SQLSTATE to 00000 and SQLCODE to 0. If a procedure needs to save the error status, it must do an assignment of the value immediately after execution of the statement which caused the error warning.

Using exception handlers in procedures and triggers
It is often desirable to intercept certain types of errors and handle them within a procedure or trigger, rather than pass the error back to the calling environment. This is done through the use of an exception handler. You define an exception handler with the EXCEPTION part of a compound statement (see "Using compound statements" on page 460). Whenever an error occurs in the compound statement, the exception handler executes. Unlike errors, warnings do not cause exception handling code to be executed. Exception handling code also executes if an error appears in a nested compound statement or in a procedure or trigger invoked anywhere within the compound statement. Drop the procedures Remember to drop both the InnerProc and OuterProc procedures by entering the following commands in the command window before continuing with the tutorial:
DROP PROCEDURE OuterProc; DROP PROCEDURE InnerProc

The demonstration procedures used to illustrate exception handling are based on those used in "Default error handling in procedures and triggers" on page 474. In this case, additional code handles the column not found error in the InnerProc procedure.
CREATE PROCEDURE OuterProc() BEGIN MESSAGE ’Hello from OuterProc.’ TO CLIENT; CALL InnerProc(); MESSAGE ’SQLSTATE set to ’, SQLSTATE,’ in OuterProc.’ TO CLIENT

479

Errors and warnings in procedures and triggers
END CREATE PROCEDURE InnerProc() BEGIN DECLARE column_not_found EXCEPTION FOR SQLSTATE ’52003’; MESSAGE ’Hello from InnerProc.’ TO CLIENT; SIGNAL column_not_found; MESSAGE ’Line following SIGNAL.’ TO CLIENT; EXCEPTION WHEN column_not_found THEN MESSAGE ’Column not found handling.’ TO CLIENT; WHEN OTHERS THEN RESIGNAL ; END

The EXCEPTION statement declares the exception handler itself. The lines following the EXCEPTION statement do not execute unless an error occurs. Each WHEN clause specifies an exception name (declared with a DECLARE statement) and the statement or statements to be executed in the event of that exception. The WHEN OTHERS THEN clause specifies the statement(s) to be executed when the exception that occurred does not appear in the preceding WHEN clauses. In this example, the statement RESIGNAL passes the exception on to a higher-level exception handler. RESIGNAL is the default action if WHEN OTHERS THEN is not specified in an exception handler. The following statement executes the OuterProc procedure:
CALL OuterProc();

The Interactive SQL Messages window then displays the following:
Hello from OuterProc. Hello from InnerProc. Column not found handling. SQLSTATE set to 00000 in OuterProc.

Notes

♦ ♦

The EXCEPTION statements execute, rather than the lines following the SIGNAL statement in InnerProc. As the error encountered was a column not found error, the MESSAGE statement included to handle the error executes, and SQLSTATE resets to zero (indicating no errors). After the exception handling code executes, control passes back to
OuterProc, which proceeds as if no error was encountered.

480

Chapter 15 Using Procedures, Triggers, and Batches
♦ You should not use ON EXCEPTION RESUME together with explicit exception handling. The exception handling code is not executed if ON EXCEPTION RESUME is included. If the error handling code for the column not found exception is simply a RESIGNAL statement, control passes back to the OuterProc procedure with SQLSTATE still set at the value 52003. This is just as if there were no error handling code in InnerProc. Since there is no error handling code in OuterProc, the procedure fails.

Exception handling and atomic compound statements

When an exception is handled inside a compound statement, the compound statement completes without an active exception and the changes before the exception are not reversed. This is true even for atomic compound statements. If an error occurs within an atomic compound statement and is explicitly handled, some but not all of the statements in the atomic compound statement are executed.

Nested compound statements and exception handlers
The code following a statement that causes an error executes only if an ON EXCEPTION RESUME clause appears in a procedure definition. You can use nested compound statements to give you more control over which statements execute following an error and which do not. Drop the procedures Remember to drop both the InnerProc and OuterProc procedures by entering the following commands in the command window before continuing with the tutorial:
DROP PROCEDURE OuterProc; DROP PROCEDURE InnerProc

The following demonstration procedure illustrates how nested compound statements can be used to control flow. The procedure is based on that used as an example in "Default error handling in procedures and triggers" on page 474.
CREATE PROCEDURE InnerProc() BEGIN BEGIN DECLARE column_not_found EXCEPTION FOR SQLSTATE VALUE ’52003’; MESSAGE ’Hello from InnerProc’ TO CLIENT; SIGNAL column_not_found; MESSAGE ’Line following SIGNAL’ TO CLIENT EXCEPTION WHEN column_not_found THEN MESSAGE ’Column not found handling’ TO CLIENT;

481

Errors and warnings in procedures and triggers
WHEN OTHERS THEN RESIGNAL; END; MESSAGE ’Outer compound statement’ TO CLIENT; END

The following statement executes the InnerProc procedure:
CALL InnerProc();

The Interactive SQL Messages window then displays the following:
Hello from InnerProc Column not found handling Outer compound statement

When the SIGNAL statement that causes the error is encountered, control passes to the exception handler for the compound statement, and the Column not found handling message prints. Control then passes back to the outer compound statement and the Outer compound statement message prints. If an error other than column not found is encountered in the inner compound statement, the exception handler executes the RESIGNAL statement. The RESIGNAL statement passes control directly back to the calling environment, and the remainder of the outer compound statement is not executed.

482

Chapter 15 Using Procedures, Triggers, and Batches

Using the EXECUTE IMMEDIATE statement in procedures
The EXECUTE IMMEDIATE statement allows statements to be constructed inside procedures using a combination of literal strings (in quotes) and variables. For example, the following procedure includes an EXECUTE IMMEDIATE statement that creates a table.
CREATE PROCEDURE CreateTableProc( IN tablename char(30) ) BEGIN EXECUTE IMMEDIATE ’CREATE TABLE ’ || tablename || ’(column1 INT PRIMARY KEY)’ END

In ATOMIC compound statements, you cannot use an EXECUTE IMMEDIATE statement that causes a COMMIT, as COMMITs are not allowed in that context. The EXECUTE IMMEDIATE statement does not support statements or queries that return result sets.

$ For more information about the EXECUTE IMMEDIATE statement,
see "EXECUTE IMMEDIATE statement" on page 518 of the book ASA Reference.

483

Transactions and savepoints in procedures and triggers

Transactions and savepoints in procedures and triggers
SQL statements in a procedure or trigger are part of the current transaction (see "Using Transactions and Isolation Levels" on page 381). You can call several procedures within one transaction or have several transactions in one procedure. COMMIT and ROLLBACK are not allowed within any atomic statement (see "Atomic compound statements" on page 461). Note that triggers are fired due to an INSERT, UPDATE, or DELETE which are atomic statements. COMMIT and ROLLBACK are not allowed in a trigger or in any procedures called by a trigger. Savepoints (see "Savepoints within transactions" on page 385) can be used within a procedure or trigger, but a ROLLBACK TO SAVEPOINT statement can never refer to a savepoint before the atomic operation started. Also, all savepoints within an atomic operation are released when the atomic operation completes.

484

Chapter 15 Using Procedures, Triggers, and Batches

Some tips for writing procedures
This section provides some pointers for developing procedures.

Check if you need to change the command delimiter
You do not need to change the command delimiter in Interactive SQL or Sybase Central when you write procedures. However, if you create and test procedures and triggers from some other browsing tool, you may need to change the command delimiter from the semicolon to another character. Each statement within the procedure ends with a semicolon. For some browsing applications to parse the CREATE PROCEDURE statement itself, you need the command delimiter to be something other than a semicolon. If you are using an application that requires changing the command delimiter, a good choice is to use two semicolons as the command delimiter (;;) or a question mark (?) if the system does not permit a multicharacter delimiter.

Remember to delimit statements within your procedure
You should terminate each statement within the procedure with a semicolon. Although you can leave off semicolons for the last statement in a statement list, it is good practice to use semicolons after each statement. The CREATE PROCEDURE statement itself contains both the RESULT specification and the compound statement that forms its body. No semicolon is needed after the BEGIN or END keywords, or after the RESULT clause.

Use fully-qualified names for tables in procedures
If a procedure has references to tables in it, you should always preface the table name with the name of the owner (creator) of the table. When a procedure refers to a table, it uses the group memberships of the procedure creator to locate tables with no explicit owner name specified. For example, if a procedure created by user_1 references Table_B and does not specify the owner of Table_B, then either Table_B must have been created by user_1 or user_1 must be a member of a group (directly or indirectly) that is the owner of Table_B. If neither condition is met, a table not found message results when the procedure is called. 485

Some tips for writing procedures
You can minimize the inconvenience of long fully qualified names by using a correlation name to provide a convenient name to use for the table within a statement. Correlation names are described in "FROM clause" on page 532 of the book ASA Reference.

Specifying dates and times in procedures
When dates and times are sent to the database from procedures, they are sent as strings. The date part of the string is interpreted according to the current setting of the DATE_ORDER database option. As different connections may set this option to different values, some strings may be converted incorrectly to dates, or the database may not be able to convert the string to a date. You should use the unambiguous date format yyyy-mm-dd or yyyy/mm/dd when using data strings within procedures. The server interprets these strings unambiguously as dates, regardless of the DATE_ORDER database option setting.

$ For more information on dates and times, see "Date and time data
types" on page 277 of the book ASA Reference.

Verifying that procedure input arguments are passed correctly
One way to verify input arguments is to display the value of the parameter in the Interactive SQL Messages window using the MESSAGE statement. For example, the following procedure simply displays the value of the input parameter var:
CREATE PROCEDURE message_test (IN var char(40)) BEGIN MESSAGE var TO CLIENT; END

You can also use the stored procedure debugger.

486

Chapter 15 Using Procedures, Triggers, and Batches

Statements allowed in batches
All SQL statements are acceptable in batches (including data definition statements such as CREATE TABLE, ALTER TABLE, and so on), with the exception of the following: ♦ ♦ ♦ ♦ ♦ CONNECT or DISCONNECT statement ALTER PROCEDURE or ALTER FUNCTION statement CREATE TRIGGER statement Interactive SQL commands such as INPUT or OUTPUT You cannot use host variables in batches.

The CREATE PROCEDURE statement is allowed, but must be the final statement of the batch. Therefore a batch can contain only a single CREATE PROCEDURE statement.

Using SELECT statements in batches
You can include one or more SELECT statements in a batch. The following is a valid batch:
IF EXISTS( SELECT * FROM SYSTABLE WHERE table_name=’employee’ )

THEN SELECT emp_lname AS LastName, emp_fname AS FirstName FROM employee; SELECT lname, fname FROM customer; SELECT last_name, first_name FROM contact; END IF

The alias for the result set is necessary only in the first SELECT statement, as the server uses the first SELECT statement in the batch to describe the result set. A RESUME statement is necessary following each query to retrieve the next result set.

487

Calling external libraries from procedures

Calling external libraries from procedures
You can call a function in an external library from a stored procedure or user-defined function. You can call functions in a DLL under Windows operating systems, in an NLM under NetWare, and in a shared object on UNIX. You cannot call external functions on Windows CE. This section describes how to use the external library calls in procedures. External libraries called from procedures share the memory of the server. If you call a DLL from a procedure and the DLL contains memory-handling errors, you can crash the server or corrupt your database. Ensure that you thoroughly test your libraries before deploying them on production databases. The API described in this section replaces an older API. Libraries written to the older API, used in versions before version 7.0, are still supported, but in new development you should use the new API. Adaptive Server Anywhere includes a set of system procedures that make use of this capability, for example to send MAPI e-mail messages.

$ For information on system procedures, see "System Procedures and
Functions" on page 961 of the book ASA Reference.

Creating procedures and functions with external calls
This section presents some examples of procedures and functions with external calls.
DBA authority required

You must have DBA authority to create procedures or functions that reference external libraries. This requirement is more strict than the RESOURCE authority required for creating other procedures or functions. Syntax You can create a procedure that calls a function function_name in DLL library.dll as follows:
CREATE PROCEDURE dll_proc ( parameter-list ) EXTERNAL NAME ’function_name@library.dll’

If you call an external DLL from a procedure, the procedure cannot carry out any other tasks; it just forms a wrapper around the DLL. An analogous CREATE FUNCTION statement is as follows:

488

Chapter 15 Using Procedures, Triggers, and Batches
CREATE FUNCTION dll_func ( parameter-list ) RETURNS data-type EXTERNAL NAME ’function_name@library.dll’

In these statements, function_name is the exported name of a function in the dynamic link library, and library.dll is the name of the library. The arguments in parameter-list must correspond in type and order to the argument expected by the library function. The library function accesses the procedure argument using an API described in "External function prototypes" on page 490. Any value returned by the external function is in turn returned by the procedure to the calling environment. No other statements permitted A procedure that references an external function can include no other statements: its sole purpose is to take arguments for a function, call the function, and return any value and returned arguments from the function to the calling environment. You can use IN, INOUT, or OUT parameters in the procedure call in the same way as for other procedures: the input values get passed to the external function, and any parameters modified by the function are returned to the calling environment in OUT or INOUT parameters. You can specify operating-system dependent calls, so that a procedure calls one function when run on one operating system, and another function (presumably analogous) on another operating system. The syntax for such calls involves prefixing the function name with the operating system name. For example:
CREATE PROCEDURE dll_proc ( parameter-list ) EXTERNAL NAME ’Windows95:95_fn@95_lib.dll;WindowsNT:nt_fn@nt_lib.dll’

System-dependent calls

The operating system identifier must be one of WindowsNT, Windows95, UNIX, or NetWare. If the list of functions does not contain an entry for the operating system on which the server is running, but the list does contain an entry without an operating system specified, the database server calls the function in that entry. NetWare calls have a slightly different format than the other operating systems. All symbols are globally known under NetWare, so any symbol (such as a function name) exported must be unique to all NLMs on the system. Consequently, the NLM name is not necessary in the call, and the call has the following syntax:
CREATE PROCEDURE dll_proc ( parameter-list ) EXTERNAL NAME ’NetWare:nw_fn’

There is no need to provide a library name. If you do provide one, it is ignored.

489

Calling external libraries from procedures

$ For a full description of the CREATE PROCEDURE statement syntax,
see "CREATE PROCEDURE statement" on page 453 of the book ASA Reference.

$ For a full description of the CREATE FUNCTION statement syntax,
see "CREATE FUNCTION statement" on page 445 of the book ASA Reference.

External function prototypes
This section describes the API for functions in external libraries. The API is defined by a header file named extfnapi.h, in the h subdirectory of your SQL Anywhere Studio installation directory. This header file handles the platform-dependent features of external function prototypes. Declaring the API version To notify the database server that the library is not written using the old API, you must provide a function as follows:
uint32 extfn_use_new_api( )

The function returns an unsigned 32-bit integer. If the return value is nonzero, the database server assumes that you are not using the old API. If the function is not exported by the DLL, the database server assumes that the old API is in use. When using the new API, the returned value must be the API version number defined in extfnapi.h. Function prototypes The name of the function must match that referenced in the CREATE PROCEDURE or CREATE FUNCTION statement. The function declaration must be as follows:
void function-name( an_extfn_api *api, void *argument-handle )

The function must return void, and must take as arguments a structure used to pass the arguments, and a handle to the arguments provided by the SQL procedure. The an_extfn_api structure has the following form:

490

Chapter 15 Using Procedures, Triggers, and Batches
typedef struct an_extfn_api { short (SQL_CALLBACK *get_value)( void * arg_handle, a_sql_uint32 arg_num, an_extfn_value *value ); short (SQL_CALLBACK *get_piece)( void * arg_handle, a_sql_uint32 arg_num, an_extfn_value *value, a_sql_uint32 offset ); short (SQL_CALLBACK *set_value)( void * arg_handle, a_sql_uint32 arg_num, an_extfn_value *value short append ); void (SQL_CALLBACK *set_cancel)( void * arg_handle, void * cancel_handle ); } an_extfn_api;

The an_extfn_value structure has the following form:
typedef struct an_extfn_value { void * data; a_sql_uint32 piece_len; union { a_sql_uint32 total_len; a_sql_uint32 remain_len; } len; a_sql_data_type type; } an_extfn_value;

Notes

Calling get_value on an OUT parameter returns the data type of the argument, and returns data as NULL. The get_piece function for any given argument can only be called immediately after the get_value function for the same argument, To return NULL, set data to NULL in an_extfn_value. The append field of set_value determines whether the supplied data replaces (false) or appends to (true) the existing data. You must call set_value with append=FALSE before calling it with append=TRUE for the same argument. The append field is ignored for fixed length data types. The header file itself contains some additional notes.

$ For information about passing parameters to external functions, see
"Passing parameters to external functions" on page 492. 491

Calling external libraries from procedures

Implementing cancel processing

An external function that expects to be canceled must inform the database server by calling the set_cancel API function. You must export a special function to enable external operations to be canceled. This function must have the following form:
void an_extfn_cancel( void * cancel_handle )

If the DLL does not export this function, the database server ignores any user interrupts for functions in the DLL. In this function, cancel_handle is a pointer provided by the function being cancelled to the database server upon each call to the external function by the set_cancel API function listed in the an_extfn_api structure, above.

Passing parameters to external functions
Data types The following SQL data types can be passed to an external library:
SQL data type CHAR VARCHAR LONG VARCHAR BINARY LONG BINARY TINYINT [ UNSIGNED ] SMALLINT [ UNSIGNED ] INT [ UNSIGNED ] BIGINT VARBINARY REAL DOUBLE C type Character data, with a specified length Character data, with a specified length Character data, with a specified length Binary data, with a specified length Character data, with a specified length 1-byte integer [ Unsigned ] 2-byte integer [ Unsigned ] 4-byte integer [ Unsigned ] 8-byte integer Binary data, with a specified length Single precision floating point number Double precision floating point number

You cannot use date or time data types, and you cannot use the exact NUMERIC data type. To provide values for INOUT or OUT parameters, use the set_value API function. To read IN and INOUT parameters, use the get_value API function. Passing NULL You can pass NULL as a valid value for all arguments. Functions in external libraries can supply NULL as a return type for any data type.

492

Chapter 15 Using Procedures, Triggers, and Batches

External function return types

The following table lists the supported return types, and how they map to the return type of the SQL function or procedure.
C data type void char * long float double SQL data type Used for external procedures. function returning CHAR(). function returning INTEGER function returning FLOAT function returning DOUBLE.

If a function in the external library returns NULL, and the SQL external function was declared to return CHAR(), then the return value of the SQL extended function is NULL.

493

Calling external libraries from procedures

494

C H A P T E R

1 6

Automating Tasks Using Schedules and Events

About this chapter

This chapter describes how to use scheduling and event handling features of Adaptive Server Anywhere to automate database administration and other tasks.
Topic Introduction Understanding schedules Understanding events Understanding event handlers Schedule and event internals Scheduling and event handling tasks Page 496 498 500 504 506 508

Contents

495

Introduction

Introduction
Many database administration tasks are best carried out systematically. For example, a regular backup procedure is an important part of proper database administration procedures. You can automate routine tasks in Adaptive Server Anywhere by adding an event to a database, and providing a schedule for the event. Whenever one of the times in the schedule passes, a sequence of actions called an event handler is executed by the database server. Database administration also requires taking action when certain conditions occur. For example, it may be appropriate to e-mail a notification to a system administrator when a disk containing the transaction log is filling up, so that the administrator can handle the situation. These tasks too can be automated by defining event handlers for one of a set of system events. Chapter contents This chapter contains the following material: ♦ ♦ An introduction to scheduling and event handling (this section). Concepts and background information to help you design and use schedules and event handlers: ♦ ♦ ♦ ♦ ♦ ♦ ♦ ♦ Questions and answers "Understanding schedules" on page 498. "Understanding events" on page 500.

A discussion of techniques for developing event handlers: "Developing event handlers" on page 504.

Internals information: "Schedule and event internals" on page 506.

Step by step instructions for how to carry out automation tasks. "Scheduling and event handling tasks" on page 508.
Consider reading... "Understanding schedules" on page 498. "Understanding events" on page 500 "Understanding event handlers" on page 504 "Developing event handlers" on page 504

To answer the question... What is a schedule? What is a system event? What is an event handler? How do I debug event handlers?

496

Chapter 16 Automating Tasks Using Schedules and Events
To answer the question... How does the database server use schedules to trigger event handlers? How can I schedule regular backups? What kind of system events can the database server use to trigger event handlers? What connection do event handlers get executed on? How do event handlers get information about what triggered them? Consider reading... "How the database server checks for scheduled times" on page 506 For an example, see "Understanding schedules" on page 498. "Understanding events" on page 500. "CREATE EVENT statement" on page 435 of the book ASA Reference. "How event handlers are executed" on page 507. "Developing event handlers" on page 504 "EVENT_PARAMETER function" on page 336 of the book ASA Reference

497

Understanding schedules

Understanding schedules
By scheduling activities you can ensure that a set of actions is executed at a set of preset times. The scheduling information and the event handler are both stored in the database itself. You can define complex schedules by associating more than one schedule with a named event. The following examples give some ideas for scheduled actions that may be useful. Examples Carry out an incremental backup daily at 1:00 am:
create event IncrementalBackup schedule start time ’1:00 AM’ every 24 hours handler begin backup database directory ’c:\\backup’ transaction log only transaction log rename match end

Summarize orders at the end of each business day:
create event Summarize schedule start time ’6:00 pm’ on ( ’Mon’, ’Tue’, ’Wed’, ’Thu’, ’Fri’ ) handler begin insert into dba.OrderSummary select max( date_ordered ), count( * ), sum( amount ) from dba.Orders where date_ordered = current date end

Defining schedules
Schedule definitions have several components to them, to permit flexibility: ♦
Name

Each schedule definition has a name. You can assign more than one schedule to a particular event, which can be useful in designing complex schedules.

♦ 498

Start time You can define a start time for the event, which is the time that it is first executed.

Chapter 16 Automating Tasks Using Schedules and Events
♦ ♦
Range

As an alternative to a start time, you can specify a range of times for which the event is active.

Recurrence

Each schedule can have a recurrence. The event is triggered on a frequency that can be given in hours, minutes, or seconds, on a set of days that can be specified as days of the week or days of the month.

499

Understanding events

Understanding events
The database server tracks several kinds of system events. Event handlers are triggered when the system event is checked by the database server, and satisfies a provided trigger condition. By defining event handlers to execute when a chosen system event occurs and satisfies a trigger condition that you define, you can improve the security and safety of your data, and help to ease administration.

$ For information on the available system events, see "Choosing a system
event" on page 500. For information on trigger conditions, see "Defining trigger conditions for events" on page 501.

Choosing a system event
Adaptive Server Anywhere tracks several system events. Each system event provides a hook on which you can hang a set of actions. The database server tracks the events for you, and executes the actions (as defined in the event handler) when needed. The available system events include the following: ♦ ♦ ♦
Backup You can use the BackupEnd event type to take actions at the end of a backup. DatabaseStart

The database is started.

Connection events

When a connection is made (Connect) or when a connection attempt fails (ConnectFailed). You may want to use these events for security purposes.

Free disk space

Tracks the available disk space on the device holding the database file (DBDiskSpace), the log file (LogDiskSpace), or temporary file (TempDiskSpace). This system event is not available on the following operating systems: ♦ ♦ Windows 95 before OSR2. Windows CE

You may want to use disk space events to alert administrators in case of a disk space shortage. ♦
File size The file reaches a specified size. This can be used for the database file (GrowDB), the transaction log (GrowLog), or the temporary file (GrowTemp).

500

Chapter 16 Automating Tasks Using Schedules and Events
You may want to use file size events to track unusual actions on the database, or monitor bulk operations. ♦ ♦
SQL errors When an error is triggered, you can use the RAISERROR event type to take actions. Idle time

The database server has been idle for a specified time. You may want to use this event type to carry out routine maintenance operations at quiet times.

Defining trigger conditions for events
Each event definition has a system event associated with it. It also has one or more trigger conditions. The event handler is triggered when the trigger conditions for the system event are satisfied. The trigger conditions are included in the WHERE clause of the CREATE EVENT statement, and can be combined using the AND keyword. Each trigger condition is of the following form:
event_condition( condition-name ) comparison-operator value

The condition-name argument is one of a set of preset strings, which are appropriate for different event types. For example, you can use DBSize (the database file size in Megabytes) to build a trigger condition suitable for the GrowDB system event. The database server does not check that the condition-name matches the event type: it is your responsibility to ensure that the condition is meaningful in the context of the event type. Examples ♦ Limit the transaction log size to 10Mb:
create event LogLimit type GrowLog where event_condition( ’LogSize’ ) > 10 handler begin backup database directory ’c:\\logs’ transaction log only transaction log rename match end

Notify an administrator when free disk space on the device containing the database file falls below 10%, but do not execute the handler more than once every five minutes (300 seconds):

501

Understanding events
create event LowDBSpace type DBDiskSpace where event_condition( ’DBFreePercent’ ) < 10 and event_condition( ’Interval’ ) >= 300 handler begin call xp_sendmail( recipient=’DBAdmin’, subject=’Low disk space’, "message"=’Database free disk space ’ || event_parameter( ’DBFreeSpace’ ) ); end

Notify an administrator of a possible attempt to break into the database:
create event SecurityCheck type ConnectFailed handler begin declare num_failures int; declare mins int; insert into FailedConnections( log_time ) values ( current timestamp ); select count( * ) into num_failures from FailedConnections where log_time >= dateadd( minutes, -5, current timestamp ); if( num_failures >= 3 ) then select datediff( minutes, last_notification, current timestamp ) into mins from Notification; if( mins > 30 ) then update Notification set last_notification = current timestamp; call xp_sendmail( recipient=’DBAdmin’, subject=’Security Check’, "message"= ’over 3 failed connections in last 5 minutes’ ) end if end if end

Run a process when the server has been idle for ten minutes. Do not execute more frequently than once per hour:

502

Chapter 16 Automating Tasks Using Schedules and Events
create event Soak type ServerIdle where event_condition( ’IdleTime’ ) >= 600 and event_condition( ’Interval’ ) >= 3600 handler begin message ’ Insert your code here ... ’ end

503

Understanding event handlers

Understanding event handlers
Event handlers execute on a separate connection from the action that triggered the event, and so do not interact with client applications. They execute with the permissions of the creator of the event.

Developing event handlers
Event handlers, whether for scheduled events or for system event handling, contain compound statements, and are similar in many ways to stored procedures. You can add loops, conditional execution, and so on, and you can use the Adaptive Server Anywhere debugger to debug event handlers. Context information for event handlers One difference between event handlers and stored procedures is that event handlers do not take any arguments. Certain information about the context in which an event was triggered is available through the event_parameter function, which supplies information about the connection that caused an event to be triggered (connection ID, user ID), as well as the event name and the number of times it has been executed.

$ For more information, see "EVENT_PARAMETER function" on
page 336 of the book ASA Reference. Testing event handlers During development, you want event handlers to be triggered at convenient times. You can use the TRIGGER EVENT statement to explicitly cause an event to execute, even when the trigger condition or scheduled time has not occurred. However, TRIGGER EVENT does not cause disabled event handlers to be executed.

$ For more information, see "TRIGGER EVENT statement" on page 630
of the book ASA Reference. While it is not good practice to develop event handlers on a production database, you can disable event handlers from Sybase Central or explicitly using the ALTER EVENT statement. It can be useful to use a single set of actions to handle multiple events. For example, you may want to take a notification action if disk space is limited on any of the devices holding the database or log files. To do this, create a stored procedure and call it in the body of each event handler. Debugging event handlers Debugging event handlers is very similar to debugging stored procedures. The event handlers appear in the procedures list. One difference is that, because each event handler runs on its own connection, you must be sure to select All connections before setting a breakpoint in an event handler. 504

Chapter 16 Automating Tasks Using Schedules and Events

$ For step-by-step instructions, see "Debugging an event handler" on
page 510.

505

Schedule and event internals

Schedule and event internals
This section describes how the database server processes schedules and event definitions.

How the database server checks for events
Events are classified according to their event type, as specified directly in the CREATE EVENT statement or using Sybase Central. The event types are of two kinds: ♦
Active event types Some event types are the result of action by the database server itself. These active event types include growing database files, or the start and end of different database actions (BackupEnd and so on) or RAISERROR.

When the database server takes the action, it checks to see whether the trigger conditions defined in the WHERE clause are satisfied, and if so triggers any events defined for that event type. ♦
Polled event types Some event types are not triggered solely by database actions. The free disk space types (DBDiskSpace and so on) as well as the IdleTime types are of this kind.

For these types of events, the database server polls every thirty seconds, starting approximately thirty seconds after the database server is started. For the IdleTime event type, the database server checks whether the server has been idle for the entire thirty seconds. If no requests have started and none are currently active, it adds the idle check interval time in seconds to the idle time total; otherwise, the idle time total is reset to 0. The value for IdleTime is therefore always a multiple of thirty seconds. When IdleTime is greater than the interval specified in the trigger condition, event handlers associated with IdleTime are fired.

How the database server checks for scheduled times
The calculation of scheduled event times is done when the database server starts, and each time a scheduled event handler completes. The calculation of the next scheduled time is based on the increment specified in the schedule definition, with the increment being added to the previous start time. If the event handler takes longer to execute than the specified increment, so that the next time is earlier than the current time, the database server increments until the next scheduled time is in the future. 506

Chapter 16 Automating Tasks Using Schedules and Events
An event handler that takes sixty-five minutes to execute and is requested to run every hour between 9:00 and 5:00 will run every two hours, at 9:00, 11:00, 1:00, and so on. To run a process such that it operates between 9:00 and 5:00 and delays for some period before the next execution, you could define a handler to loop until its completion time has passed, with a sleep instruction, perhaps using xp_cmdshell, between each iteration. If you are running a database server intermittently, and it is not running at a scheduled time, the event handler does not run at startup. Instead, the next scheduled time is computed at startup. If, for example, you schedule a backup to take place every night at one o’clock, but regularly shut down the database server at the end of each work day, the backup never takes place.

How event handlers are executed
When an event handler is triggered, a temporary internal connection is made, on which the event handler is executed. The handler is not executed on the connection that caused the handler to be triggered, and consequently statements such as MESSAGE .. TO CLIENT, which interact with the client application, are not meaningful within event handlers. The temporary connection on which the handler is executed does not count towards the connection limit for licensing purposes. Event creation requires DBA authority, and events execute with the permissions of their creator. If you wish event handlers to execute with nonDBA authority, you can call a procedure from within the handler, as stored procedures run with the permissions of their creator. Any event errors are logged to the server console.

507

Scheduling and event handling tasks

Scheduling and event handling tasks
This section collects together instructions for tasks related to automating tasks with schedules and events.

Adding a schedule or event to a database
Schedules and events are handled in a similar fashion, both from Sybase Central and in SQL.

$ For background information, see "Understanding schedules" on
page 498, and "Understanding events" on page 500.
v To add a schedule or event to a database (Sybase Central):

1 2 3 4

Connect to the database as a user with DBA authority. Open the Events folder for your database. Double-click Add Event. The Event Creation wizard appears. Follow the instructions in the wizard. The Wizard contains many options, depending on the schedule or event you wish to create. These are explained in detail in other tasks.

v To add a schedule or event to a database (SQL):

1 2

Connect to the database as a user with DBA authority. Execute a CREATE EVENT statement. The CREATE EVENT contains many options, depending on the schedule or event you wish to create. These are explained in detail in other tasks.

$ For more information, see "CREATE EVENT statement" on
page 435 of the book ASA Reference.

Adding a manually-triggered event to a database
If you create an event handler without a schedule or system event to trigger it, it is executed only when manually triggered.
v To add a manually-triggered event to a database (Sybase Central):

1 508

Connect to the database as a user with DBA authority.

Chapter 16 Automating Tasks Using Schedules and Events
2 3 4 5 6 7 8 Open the Events folder for your database. Double-click Add Event. The Event Creation Wizard is displayed. Enter a name for the event, and click Next. Select Triggered Manually, and click Next. Enter the SQL statements for your event handler, and click Next. Select Event is Enabled, and select Execute at all Locations, and click Next. Enter a comment describing the event, and click Finish to add the event to the database.

If you wish to accept the default values for all remaining options, you can click Finish at an earlier stage of the wizard.
v To add a manually-triggered event to a database (SQL):

1 2

Connect to the database as a user with DBA authority. Execute a CREATE EVENT statement with no schedule or WHERE clause. The restricted syntax of the CREATE EVENT is as follows:
CREATE EVENT event-name HANDLER BEGIN … event handler END

If you are developing event handlers, you can add schedules or system events to control the triggering of an event later, either using Sybase Central or the ALTER EVENT statement.

$ See also:
♦ ♦ For information on triggering events, see "Triggering an event handler" on page 510. For information on altering events, see "ALTER EVENT statement" on page 387 of the book ASA Reference.

509

Scheduling and event handling tasks

Triggering an event handler
Any event handler can be triggered manually, in addition to those occasions when it executes because of a schedule or system event. Triggering events manually can be useful during development of event handlers, and also, for certain events, in production environments. For example, you may have a monthly sales report scheduled, but from time to time you may want to obtain a sales report for a reason other than the end of the month.

$ For information on developing event handlers, see "Developing event
handlers" on page 504.
v To trigger an event handler (Sybase Central):

1 2 3 4

Connect to the database as a user with DBA authority. Open the Events folder for your database. Right-click the event you wish to trigger and choose Trigger from the popup menu. The Event Parameters dialog is displayed. Supply any parameters the event handler requires, in the following form:
parameter=value;parameter=value

Click OK to trigger the event handler.
v To trigger an event handler (SQL):

1 2

Connect to the database as a user with DBA authority. Execute the TRIGGER EVENT statement, supplying the name of the event. For example:
TRIGGER EVENT sales_report_event

$ For more information, see "TRIGGER EVENT statement" on
page 630 of the book ASA Reference.

Debugging an event handler
Debugging is a regular part of any software development. Event handlers can be debugged during the development process.

$ For information on developing event handlers, see "Developing event
handlers" on page 504.

$ For information on using the debugger, see "Debugging Logic in the
Database" on page 621.

510

Chapter 16 Automating Tasks Using Schedules and Events
v To debug an event handler:

1

Start the Adaptive Server Anywhere debugger. From the Start menu, choose Programs®Sybase SQL Anywhere 7® Adaptive Server Anywhere 7®Debug Database Objects.

2 3 4 5 6

In the Connections window, double click All Connections. In the procedures window, double click the event you wish to debug. The event definition is displayed in the Source window. In the Source window, set a breakpoint. From Interactive SQL or another application, trigger the event handler using the TRIGGER EVENT statement. The execution stops at the breakpoint you have set. You can now use the debugger features to trace execution, local variables, and so on.

511

Scheduling and event handling tasks

512

C H A P T E R

1 7

Welcome to Java in the Database

About this chapter

This chapter provides motivation and concepts for using Java in the database. Adaptive Server Anywhere is a runtime environment for Java or Java platform. Java provides a natural extension to SQL, turning Adaptive Server Anywhere into a platform for the next generation of enterprise applications.

Contents

Topic Introduction to Java in the database Java in the database Q & A A Java seminar The runtime environment for Java in the database A Java in the database exercise

Page 514 517 523 533 541

513

Introduction to Java in the database

Introduction to Java in the database
Adaptive Server Anywhere is a runtime environment for Java. This means that Java classes can be executed in the database server. Building a runtime environment for Java classes into the database server provides powerful new ways of managing and storing data and logic. Java in the database offers the following: ♦ You can reuse Java components in the different layers of your application—client, middle-tier, or server—and use them wherever makes most sense to you. Adaptive Server Anywhere becomes a platform for distributed computing. Java is a more powerful language than stored procedures for building logic into the database. Java classes become rich user-defined data types. Methods of Java classes provide new functions accessible from SQL. Java can be used in the database without jeopardizing the integrity, security and robustness of the database.

♦ ♦ ♦ ♦ The SQLJ proposed standard

The Adaptive Server Anywhere Java implementation is based on the SQLJ Part 1 and SQLJ Part 2 proposed standards. SQLJ Part 1 provides specifications for calling Java static methods as SQL stored procedures and user-defined functions. SQLJ Part 2 provides specifications for using Java classes as SQL domains.

Learning about Java in the database
Java is a relatively new programming language with a growing, but still limited, knowledge base. Intended for a variety of Java developers, this documentation will be useful for everyone from the experienced Java developer to the many readers who are unfamiliar with the language, its possibilities, syntax and use. For those readers familiar with Java, there is much to learn about using Java in a database. Sybase not only extends the capabilities of the database with Java, but also extends the capabilities of Java with the database. Java documentation The following table outlines the documentation regarding the use of Java in the database.

514

Chapter 17 Welcome to Java in the Database

Title "Welcome to Java in the Database" on page 513 (this chapter) "Using Java in the Database" on page 549 "Data Access Using JDBC" on page 591 "Debugging Logic in the Database" on page 621 Adaptive Server Anywhere Reference. Reference guide to Sun’s Java API Thinking in Java by Bruce Eckel.

Purpose Java concepts and how to apply them in Adaptive Server Anywhere. Practical steps to using Java in the database. Accessing data from Java classes, including distributed computing. Testing and debugging Java code running in the database. The Reference Manual includes material on the SQL extensions that support Java in the database. Online guide to Java API classes, fields and methods. Available as Windows Help only. Online book that teaches how to program in Java. Supplied in Adobe PDF format in the jxmp subdirectory of your Adaptive Server Anywhere installation directory.

Using the Java documentation
The following table is a guide to which parts of the Java documentation apply to you, depending on your interests and background. It is a guide only and should not limit your efforts to learn more about Java in the database.
If you ... Are new to object-oriented programming. Consider reading ... "A Java seminar" on page 523 Thinking in Java by Bruce Eckel. Want an explanation of terms such as instantiated, field and class method. Are a Java developer who wants to just get started. "A Java seminar" on page 523 "The runtime environment for Java in the database" on page 533 "A Java in the database exercise" on page 541 Want to know the key features of Java in the database. "Java in the database Q & A" on page 517

515

Introduction to Java in the database
If you ... Want to find out how to access data from Java. Want to prepare a database for Java. Want a complete list of supported Java APIs. Are trying to use a Java API class and need Java reference information. Want to see an example of distributed computing. Consider reading ... "Data Access Using JDBC" on page 591 "Java-enabling a database" on page 553 "Java class data types" on page 288 of the book ASA Reference The online guide to Java API classes (Windows Help only). "Creating distributed applications" on page 616.

516

Chapter 17 Welcome to Java in the Database

Java in the database Q & A
This section describes the key features of Java in Adaptive Server Anywhere.

What are the key features of Java in the database?
Detailed explanations of all the following points appear in later sections. ♦ ♦
You can run Java in the database server You can call Java from SQL

An internal Java Virtual Machine (VM) runs Java code in the database server. You can call Java functions (methods) from SQL statements. Java methods provide a more powerful language than SQL stored procedures for adding logic to the database. An internal JDBC driver lets you access data from Java.

♦ ♦ ♦

You can access data from Java

You can debug Java in the database You can use the Sybase Java debugger to test and debug your Java classes in the database. You can use Java classes as data types

Every Java class installed in a database becomes available as a data type that can be used as the data type of a column in a table or a variable.

You can save Java objects in tables An instance of a Java class (a Java object) can be saved as a value in a table. You can insert Java objects into a table, execute SELECT statements against the fields and methods of objects stored in a table, and retrieve Java objects from a table.

With this ability, Adaptive Server Anywhere becomes an objectrelational database, supporting objects while not degrading existing relational functionality. ♦
SQL is preserved

The use of Java does not alter the behavior of existing SQL statements or other aspects of non-Java relational database behavior.

How do I store Java instructions in the database?
Java is an object-oriented language, so its instructions (source code) come in the form of classes. To execute Java in a database, you write the Java instructions outside the database, and compile them outside the database into compiled classes (byte code), which are binary files holding Java instructions. 517

Java in the database Q & A
You then install these compiled classes into a database. Once installed, you can execute these classes in the database server. Adaptive Server Anywhere is a runtime environment for Java classes, not a Java development environment. You need a Java development environment, such as Sybase PowerJ or the Sun Microsystems Java Development Kit, to write and compile Java.

How does Java get executed in a database?
Adaptive Server Anywhere includes a Java Virtual Machine (VM), which runs in the database environment. The Sybase Java VM interprets compiled Java instructions and runs them in the database server. In addition to the VM, the SQL request processor in the database server has been extended so it can call into the VM to execute Java instructions. It can also process requests from the VM, to enable data access from Java. Differences from a standalone VM There is a difference between executing Java code using a standard VM such as the Sun Java VM java.exe and executing Java code in the database. The Sun VM is run from a command line, while the Adaptive Server Anywhere Java VM is available at all times to perform a Java operation whenever it is required as part of the execution of a SQL statement. You cannot access the Sybase Java interpreter externally. It is only used when the execution of a SQL statement requires a Java operation to take place. The database server starts the VM automatically when needed: you do not have to take any explicit action to start or stop the VM.

Why Java?
Java provides a number of features that make it ideal for use in the database: ♦ ♦ ♦ ♦ ♦ ♦ Thorough error checking at compile time. Built-in error handing with a well-defined error handling methodology. Built-in garbage collection (memory recovery). Elimination of many bug-prone programming techniques. Strong security features. Java code is interpreted, so no operations get executed without being acceptable to the VM.

518

Chapter 17 Welcome to Java in the Database

On what platforms is Java in the database supported?
Java in the database is not supported on Windows CE. It is supported on Windows 95/98, Windows NT, UNIX, and NetWare.

How do I use Java and SQL together?
A guiding principle for the design of Java in the database is that it provides a natural, open extension to existing SQL functionality. ♦
Java operations are invoked from SQL Sybase has extended the range of SQL expressions to include properties and methods of Java objects, so you can include Java operations in a SQL statement. Java classes become domains

You store Java classes using the same SQL statements as those used for traditional SQL data types.

You can use many of the classes that are part of the Java API as included in the Sun Microsystems Java Development Kit version 1.1.8. You can also use classes created and compiled by Java developers.

What is the Java API?
The Java Application Programmer’s Interface (API) is a set of classes created by Sun Microsystems. It provides a range of base functionality that can be used and extended by Java developers. It is at the core of ’what you can do’ with Java. The Java API offers a tremendous amount of functionality in its own right. A large portion of the Java API is available to any database able to use Java code. This exposes the majority of non-visual classes from the Java API that should be familiar to developers currently using the Sun Microsystems Java Development Kit (JDK).

$ For a complete list of supported Java APIs, see "Supported Java
packages" on page 288 of the book ASA Reference.

How do I access Java from SQL?
In addition to using the Java API in classes, you can use it in stored procedures and SQL statements. You can treat the Java API classes as extensions to the available built-in functions provided by SQL.

519

Java in the database Q & A
For example, the SQL function PI(*) returns the value for pi. The Java API class java.lang.Math has a parallel field named PI returning the same value. But java.lang.Math also has a field named E that returns the base of the natural logarithms, as well as a method that computes the remainder operation on two arguments as prescribed by the IEEE 754 standard. Other members of the Java API offer even more specialized functionality. For example, java.util.Stack generates a last-in, first-out queue that can store ordered lists; java.util.HashTable maps values to keys; java.util.StringTokenizer breaks a string of characters into individual word units.

Which Java classes are supported?
The database does not support all Java API classes. Some classes, for example the java.awt package containing user interface components for applications, are inappropriate inside a database server. Other classes, including parts of java.io, deal with writing information to disk, and this also is unsupported in the database server environment.

$ For a list of supported and unsupported classes, see "Supported Java
packages" on page 288 of the book ASA Reference, and "Unsupported Java packages and classes" on page 289 of the book ASA Reference.

How can I use my own Java classes in databases?
You can install your own Java classes into a database. For example, a developer could design, write in Java, and compile with a Java compiler, a user-created Employee class or Package class. User-created Java classes can contain both information about the subject and some computational logic. Once installed in a database, Adaptive Server Anywhere lets you use these classes in all parts and operations of the database and execute their functionality (in the form of class or instance methods) as easily as calling a stored procedure.
Java classes and stored procedures are different

Java classes are different from stored procedures. Whereas stored procedures are written in SQL, Java classes provide a more powerful language, and can be called from client applications as easily and in the same way as stored procedures.

520

Chapter 17 Welcome to Java in the Database
When a Java class gets installed in a database, it becomes available as a new domain. You can use a Java class in any situation where you would use builtin SQL data types: as a column type in a table or a variable type. For example, if a class called Address has been installed into a database, a column in a table called Addr can be of type Address, which means only objects based on the Address class can be saved as row values for that column.

Can I access data using Java?
The JDBC interface is an industry standard, designed specifically to access database systems. The JDBC classes are designed to connect to a database, request data using SQL statements, and return result sets that can be processed in the client application. Normally, client applications use JDBC classes, and the database system vendor supplies a JDBC driver that allows the JDBC classes to establish a connection. You can connect from a client application to Adaptive Server Anywhere via JDBC, using jConnect or a JDBC/ODBC bridge. Adaptive Server Anywhere also provides an internal JDBC driver, which permits Java classes installed in a database to use JDBC classes that execute SQL statements.

Can I move classes from client to server?
You can create Java classes that can be moved between levels of an enterprise application. The same Java class can be integrated into either the client application, a middle tier, or the database—wherever is most appropriate. You can move a class containing business logic, data or a combination of both to any level of the enterprise system, including the server, allowing you complete flexibility to make the most appropriate use of resources. It also enables enterprise customers to develop their applications using a single programming language in a multi-tier architecture with unparalleled flexibility.

521

Java in the database Q & A

Can I create distributed applications?
You can create an application that has some pieces operating in the database and some on the client machine. You can pass Java objects from the server to the client just as you pass SQL data such as character strings and numeric values.

$ For an example, see "Creating distributed applications" on page 616.

What can I not do with Java in the database?
Adaptive Server Anywhere is a runtime environment for Java classes, not a Java development environment. You cannot carry out the following tasks in the database: ♦ ♦ ♦ ♦ Edit class source files (*.java files). Compile Java class source files (*.java files). Execute unsupported Java APIs, such as applet and visual classes. Execute Java methods that require the execution of native methods. All user classes installed into the database must be 100% Java.

The Java classes used in Adaptive Server Anywhere must be written and compiled using a Java application development tool, and then installed into a database for use, testing, and debugging.

522

Chapter 17 Welcome to Java in the Database

A Java seminar
This section introduces key Java concepts. After reading this section you should be able to examine Java code, such as a simple class definition or the invocation of a method, and understand what is taking place.
Java examples directory

Some of the classes used as examples in this manual are located in the Java examples directory, jxmp, which is a subdirectory of your Adaptive Server Anywhere installation directory. Two files represent each Java class example: the Java source and the compiled class. You can immediately install to a database (without modification) the compiled version of the Java class examples.

Understanding Java classes
A Java class combines data and functionality-the ability to hold information and perform computational operations. One way of understanding the concept of a class is to view it as an entity, an abstract representation of a thing. You could design an Invoice class, for example, to mimic paper invoices, such as those used every day in business operations. Just as a paper invoice contains certain information (line-item details, who is being invoiced, the date, payment amount, payment due-date), so also does an instance of an Invoice class. Classes hold information in fields. In addition to describing data, a class can make calculations and perform logical operations. For example, the Invoice class could calculate the tax on a list of line items for every Invoice object, and add it to the sub total to produce a final total, without any user intervention. Such a class could also ensure all essential pieces of information are present in the Invoice and even indicate when payment is over due or partially paid. Calculations and other logical operations are carried out by the methods of the class. Example The following Java code declares a class called Invoice. This class declaration would be stored in a file named Invoice.java, and then compiled into a Java class using a Java compiler.

523

A Java seminar

Compiling Java classes

Compiling the source for a Java class creates a new file with the same name as the source file but with a different extension. Compiling Invoice.java creates a file called Invoice.class which could be used in a Java application and executed by a Java VM. The Sun JDK tool for compiling class declarations is javac.exe.
public class Invoice { // So far, this class does nothing and knows nothing }

The class keyword is used, followed by the name of the class. There is an opening and closing brace: everything declared between the braces, such as fields and methods, becomes part of the class. In fact, no Java code exists outside class declarations. Even the Java procedure that a Java interpreter runs automatically to create and manage other objects — the main method that is often the start of your application — is itself located within a class declaration.

Subclasses in Java
You can define classes as subclasses of other classes. A class that is a subclass of another class can use the fields and method of its parent: this is called inheritance. You can define additional methods and fields that apply only to the subclass, and redefine the meaning of inherited fields and methods. Java is a single-hierarchy language, meaning that all classes you create or use eventually inherit from one class. This means the low-level classes (classes further up in the hierarchy) must be present before higher-level classes can be used. The base set of classes required to run Java applications is called the runtime Java classes, or the Java API.

Understanding Java objects
A class is a template that defines what an object is capable of doing, just as an invoice form is a template that defines what information the invoice should contain.

524

Chapter 17 Welcome to Java in the Database
Classes contain no specific information about objects. Rather, your application creates or instantiates objects based on the class (template), and the objects hold the data or perform calculations. The instantiated object is an instance of the class. For example, an Invoice object is an instance of the Invoice class. The class defines what the object is capable of but the object is the incarnation of the class that gives the class meaning and usefulness. In the invoice example, the invoice form defines what all invoices based on that form can accomplish. There is one form and zero or many invoices based on the form. The form contains the definition but the invoice encapsulates the usefulness. The Invoice object is created, stores information, is stored, retrieved, edited, updated, and so on. Just as one invoice template can create many invoices, with each invoice separate and distinct from the other in its details, you can generate many objects from one class. Methods and fields A method is a part of a class that does something—a function that performs a calculation or interacts with other objects—on behalf of the class. Methods can accept arguments, and return a value to the calling function. If no return value is necessary, a method can return void. Classes can have any number of methods. A field is a part of a class that holds information. When you create an object of type JavaClass, the fields in JavaClass hold the state unique to that object.

Class constructors
You create an object by invoking a class constructor. Constructors are methods that have the following properties: ♦ A constructor method has the same name as the class, and has no declared data type. For example, a simple constructor for the Product class would be declared as follows:
Product () { ...constructor code here... }

♦ ♦

If you include no constructor method in your class definition, a default method is used that is provided by the Java base object. You can supply more than one constructor for each class, with different numbers and types of arguments. When a constructor is invoked, the one with the proper number and type of arguments is used.

525

A Java seminar

Understanding fields
There are two categories of Java fields: ♦
Instance fields

Each object has its own set of instance fields, created when the object was created. They hold information specific to that instance. For example, a lineItem1Description field in the Invoice class holds the description for a line item on a particular invoice. You can access instance fields only through an object reference.

Class fields A class field holds information that is independent of any particular instance. A class field is created when the class is first loaded, and no further instances are created no matter how many objects are created. Class fields can be accessed either through the class name or the object reference.

To declare a field in a class, state its type, then its name, followed by a semicolon. To declare a class field, use the static Java keyword in the declaration. You declare fields in the body of the class and not within a method; declaring a variable within a method makes it a part of the method, not of the class. Examples The following declaration of the class Invoice has four fields, corresponding to information that might be contained on two line items on an invoice.
public class Invoice { // Fields of an invoice contain the invoice data public String lineItem1Description; public int lineItem1Cost; public String lineItem2Description; public int lineItem2Cost; }

Understanding methods
There are two categories of Java methods: ♦
Instance methods

A totalSum method in the Invoice class could calculate and add the tax, and return the sum of all costs, but would only be useful if it is called in conjunction with an Invoice object, one that had values for its line item costs. The calculation can only be performed for an object, since the object (not the class) contains the line items of the invoice.

526

Chapter 17 Welcome to Java in the Database

Class methods

Class methods (also called static methods), can be invoked without first creating an object. Only the name of the class and method is necessary to invoke a class method. Similar to instance methods, class methods accept arguments and return values. Typically, class methods perform some sort of utility or information function related to the overall functionality of the class. Class methods cannot access instance fields.

To declare a method, you state its return type, its name and any parameters it takes. Like a class declaration, the method uses an opening and closing brace to identify the body of the method where the code goes.
public class Invoice { // Fields public String lineItem1Description; public double lineItem1Cost; public String lineItem2Description; public double lineItem2Cost; // A method public double totalSum() { double runningsum; runningsum = lineItem1Cost + lineItem2Cost; runningsum = runningsum * 1.15; return runningsum; } }

Within the body of the totalSum method, a variable named runningsum is declared. First, this holds the sub total of the first and second line item cost. This sub total is then multiplied by 15 per cent (the rate of taxation) to determine the total sum. The local variable (as it is known within the method body) is then returned to the calling function. When you invoke the totalSum method, it returns the sum of the two line item cost fields plus the cost of tax on those two items. Example The parseInt method of the java.lang.Integer class, which is supplied with Adaptive Server Anywhere, is one example of a class method. When given a string argument, the parseInt method returns the integer version of the string. For example given the string value "1", the parseInt method returns 1, the integer value, without requiring an instance of the java.lang.Integer class to first be created, as illustrated by this Java code fragment: 527

A Java seminar
String num = "1"; int i = java.lang.Integer.parseInt( num );

Example

The following version of the Invoice class now includes both an instance method and a class method. The class method named rateOfTaxation returns the rate of taxation used by the class to calculate the total sum of the invoice. The advantage of making the rateOfTaxation method a class method (as opposed to an instance method or field) is that other classes and procedures can use the value returned by this method without having to create an instance of the class first. Only the name of the class and method is required to return the rate of taxation used by this class. Making rateofTaxation a method, as opposed to a field, allows the application developer to change how the rate is calculated without adversely affecting any objects, applications or procedures that use its return value. Future versions of Invoice could make the return value of the rateOfTaxation class method based on a more complicated calculation without affecting other methods that use its return value.
public class Invoice { // Fields public String lineItem1Description; public double lineItem1Cost; public String lineItem2Description; public double lineItem2Cost; // An instance method public double totalSum() { double runningsum; double taxfactor = 1 + Invoice.rateOfTaxation(); runningsum = lineItem1Cost + lineItem2Cost; runningsum = runningsum * taxfactor; return runningsum; } // A class method public static double rateOfTaxation() { double rate; rate = .15; return rate; } }

528

Chapter 17 Welcome to Java in the Database

Object oriented and procedural languages
If you are more familiar with procedural languages such as C, or the SQL stored procedure language, than object-oriented languages, this section explains some of the key similarities and differences between procedural and object-oriented languages. Java is based on classes The main structural unit of code in Java is a class. A Java class could be looked at as just a collection of procedures and variables that have been grouped together because they all relate to a specific, identifiable category. However the manner in which a class gets used sets object oriented languages apart from procedural languages. When an application written in a procedural language is executed, it is typically loaded into memory once and takes the user down a pre-defined course of execution. In object-oriented languages such as Java, a class is used like a template: a definition of potential program execution. Multiple copies of the class can be created and loaded dynamically, as needed, with each instance of the class capable of containing its own data, values and course of execution. Each loaded class could be acted on or executed independently of any other class loaded into memory. A class that is loaded into memory for execution it is said to have been instantiated. An instantiated class is called an object: it is an application derived from the class that is prepared to hold unique values or have its methods executed in a manner independent of other class instances.

A Java glossary
The following items outline some of the details regarding Java classes. It is by no means an exhaustive source of knowledge about the Java language but may aid in the use of Java classes in Adaptive Server Anywhere.

$ For a thorough examination of the Java language, see the online book
Thinking in Java, by Bruce Eckel, included with Adaptive Server Anywhere in the file jxmp\Tjava.pdf. Packages A package is a grouping of classes that share a common purpose or category. One member of a package has special privileges to access data and methods in other members of the package, hence the protected access modifier. A package is the Java equivalent of a library. It is a collection of classes, which can be made available using the import statement. The following Java statement imports the utility library from the Java API: 529

A Java seminar
import java.util.*

Packages are typically held in Jar files, which have the extension .jar or .zip. Public versus private An access modifier determines the visibility (essentially the public, private or protected keyword used in front of any declaration) of a field, method or class to other Java objects. ♦ ♦ ♦ A public class, method, or field is visible everywhere. A private class, method, or field is visible only in methods defined within that class. A protected method or field is visible to methods defined within that class, within sublclasses of the class, or within other classes in the same package. The default visibility, known as package, means that the method or field is visible within the class and to other classes in the same package.

♦ Constructors

A constructor is a special method of a Java class that is called when an instance of the class is created. Classes can define their own constructors, including multiple, overriding constructors. Which arguments were used in the attempt to create the object determine which constructor is used. When the type, number and order of arguments used to create an instance of the class match one of the class’s constructors, that constructor is used when creating the object.

Garbage collection

Garbage collection automatically removes any object with no references to it, with the exception of objects stored as values in a table. There is no such thing as a destructor method in Java (as there is in C++). Java classes can define their own finalize method for clean up operations when an object is discarded during garbage collection.

Interfaces

Java classes can inherit only from one class. Java uses interfaces instead of multiple-inheritance. A class can implement multiple interfaces, each interface defines a set of methods and method profiles that must be implemented by the class for the class to be compiled. An interface defines what methods and static fields the class must declare. The implementation of the methods and fields declared in an interface is located within the class that uses the interface: the interface defines what the class must declare, it is up to the class to determine how it is implemented.

Java error handling
Java error handling code is separate from the code for normal processing.

530

Chapter 17 Welcome to Java in the Database
Errors generate an exception object representing the error. This is called throwing an exception. A thrown exception terminates a Java program unless it is caught and handled properly at some level of the application. Both Java API classes and custom-created classes can throw exceptions. In fact, users can create their own exception classes which throw their own custom-created classes. If there is no exception handler in the body of the method where the exception occurred, then the search for an exception handler continues up the call stack. If the top of the call stack is reached and no exception handler has been found, the default exception handler of the Java interpreter running the application is called and the program terminates. In Adaptive Server Anywhere, if a SQL statement calls a Java method, and an unhandled exception is thrown, a SQL error is generated. Error types in Java All errors in Java come from two types of error classes: Exception and Error. Usually, Exception-based errors are handled by error handling code in your method body. Error type errors are specifically for internal errors and resource exhaustion errors inside the Java run-time system. Exception class errors are thrown and caught. Exception handling code is characterized by try, catch and finally code blocks. A try block executes code that may generate an error. A catch block is code that executes if the execution of a try block generates (or throws) an error. A finally block defines a block of code that executes regardless of whether an error was generated and caught and is typically used for cleanup operations. It is used for code that, under no circumstances, can be omitted. There are two types of exception class errors: those that are runtime exceptions and those that are not runtime exceptions. Errors generated by the runtime system are known as implicit exceptions, in that they do not have to be explicitly handled as part of every class or method declaration. For example, an array out of bounds exception can occur whenever an array is used, but the error does not have to be part of the declaration of the class or method that uses the array. All other exceptions are explicit. If the method being invoked can throw an error, it must be explicitly caught by the class using the exception-throwing method, or this class must explicitly throw the error itself by identifying the exception it may generate in its class declaration. Essentially, explicit exceptions must be dealt with explicitly. A method must declare all the explicit errors it throws, or catch all the explicit errors that may potentially be thrown.

531

A Java seminar
Non-runtime exceptions are checked at compile time. Runtime exceptions are usually caused by errors in programming. Java catches many such errors during compilation, before running the code. Every Java method is given an alternative path of execution so that all Java methods complete, even if they are unable to complete normally. If the type of error thrown is not caught, it’s passed to the next code block or method in the stack.

532

Chapter 17 Welcome to Java in the Database

The runtime environment for Java in the database
This section describes the Sybase runtime environment for Java, and how it differs from a standard Java runtime environment.

Java version
The Sybase Java VM executes a subset of JDK version 1.1.8. Between release 1.0 of the Java Developer’s Kit (JDK) and release 1.1, several new APIs were introduced. As well, a number were deprecated-the use of certain APIs became no longer recommended and support for them may be dropped in future releases. A Java class file using deprecated APIs generates a warning when compiled, but does still execute on a Java virtual machine built to release 1.1 standards, such as the Sybase VM. The internal JDBC driver supports JDBC version 1.1.

$ For more information on the JDK 1.1 APIs that are supported, please
see "Supported Java packages" on page 288 of the book ASA Reference.

The runtime Java classes
The runtime Java classes are the low-level classes that are made available to a database when it is created or Java-enabled. These classes include a subset of the Java API. The runtime classes provide basic functionality on which to build applications. The runtime classes are always available to classes in the database. You can incorporate the runtime Java classes in your own user-created classes: either inheriting their functionality or using it within a calculation or operation in a method. Examples Some Java API classes included in the runtime Java classes include: ♦
Primitive Java data types All primitive (native) data types in Java have a corresponding class. In addition to being able to create objects of these types, the classes have additional, often useful functionality.

The Java int data type has a corresponding class in java.lang.Integer. 533

The runtime environment for Java in the database

The utility package

The package java.util.* contains a number of very helpful classes whose functionality has no parallel in the SQL functions available in Adaptive Server Anywhere. Some of the classes include: ♦
Hashtable

which maps keys to values. which breaks a String down into individual

♦ ♦ ♦ ♦

StringTokenizer

words.
Vector Stack

which holds an array of objects whose size can change dynamically which holds a last-in, first-out stack of objects.

JDBC for SQL operations The package java.sql.* contains the classes needed by Java objects to extract data from the database using SQL statements.

Unlike user-defined classes, the runtime classes are not stored in the database. Instead, they are stored in files in the java subdirectory of the Adaptive Server Anywhere installation directory.

User-defined classes
User-defined classes are installed into a database using the INSTALL statement. Once installed, they become available to other classes in the database. If they are public classes, they are available from SQL as domains.

$ For information on installing classes, see "Installing Java classes into a
database" on page 558.

Identifying Java methods and fields
The dot in SQL In SQL statements, the dot identifies columns of tables, as in the following query:
SELECT employee.emp_id FROM employee

The dot also indicates object ownership in qualified object names:
SELECT emp_id FROM dba.employee

The dot in Java

In Java, the dot is an operator that invokes the methods or access the fields of a Java class or object. It is also part of an identifier, used to identify class names, as in the fully qualified class name java.util.Hashtable.

534

Chapter 17 Welcome to Java in the Database
In the following Java code fragment, the dot is part of an identifier on the first line of code. On the second line of code, it is an operator.
java.util.Random rnd = new java.util.Random(); int i = rnd.nextInt();

Invoking Java methods from SQL

In SQL, the dot operator can be replaced with the double right angle bracket (>>). The dot operator is more Java-like, but can lead to ambiguity with respect to existing SQL names. The use of >> removes this ambiguity.
>> in SQL is not the same as >> in Java

You can only use the double right angle bracket operator in SQL statements where a Java dot operator is otherwise expected. Within a Java class, the double right angle bracket is not a replacement for the dot operator and has a completely different meaning in its role as the right bit shift operator. For example, the following batch of SQL statements is valid:
CREATE VARIABLE rnd java.util.Random; SET rnd = NEW java.util.Random(); SELECT rnd>>nextInt();

The result of the SELECT statement is a randomly generated integer. Using the variable created in the previous SQL code example, the following SQL statement illustrates the correct use of a class method.
SELECT java.lang.Math>>abs( rnd>>nextInt() );

Java is case sensitive
Java syntax works as you would expect it to, and SQL syntax is unaltered by the presence of Java classes. This is true even if the same SQL statement contains both Java and SQL syntax. It’s a simple statement but with farreaching implications. Java is case sensitive. The Java class FindOut is a completely different class from the class Findout. SQL is case insensitive with respect to keywords and identifiers. Java case sensitivity is preserved even when embedded in a SQL statement that is case insensitive. The Java parts of the statement must be case sensitive, even though the parts previous to and following the Java syntax can be in either upper or lower case. For example the following SQL statements successfully execute because the case of Java objects, classes and operators is respected, even though there is variation in the case of the remaining SQL parts of the statement. 535

The runtime environment for Java in the database
SeLeCt java.lang.Math.random();

Data types

When you use a Java class as a data type for a column, it is a user-defined SQL data type. However, it is still case sensitive. This convention prevents ambiguities with Java classes that differ only in case.

Strings in Java and SQL
A set of double quotes identifies string literals in Java, as in the following Java code fragment:
String str = "This is a string";

In SQL, however, single quotes mark strings, and double quotes indicate an identifier, as illustrated by the following SQL statement:
INSERT INTO TABLE DBA.t1 VALUES( ’Hello’ )

You should always use the double quote in Java source code, and single quotes in SQL statements. For example, the following SQL statements are valid.
CREATE VARIABLE str char(20); SET str = NEW java.lang.String( ’Brand new object’ )

The following Java code fragment is also valid, if used within a Java class.
String str = new java.lang.String( "Brand new object" );

Printing to the command line
Printing to the standard output is a quick way of checking variable values and execution results at various points of code execution. When the method in the second line of the following Java code fragment is encountered, the string argument it accepts prints out to standard output.
String str = "Hello world"; System.out.println( str );

In Adaptive Server Anywhere, standard output is the server window, so the string appears there. Executing the above Java code within the database is the equivalent of the following SQL statement.
MESSAGE ’Hello world’

536

Chapter 17 Welcome to Java in the Database

Using the main method
When a class contains a main method matching the following declaration, most Java run time environments, such as the Sun Java interpreter, execute it automatically. Normally, this static method executes only if it is the class being invoked by the Java interpreter
public static void main( String args[ ] ) { }

Useful for testing the functionality of Java objects, you are always guaranteed this method will be called first, when the Sun Java runtime system starts. In Adaptive Server Anywhere the Java runtime system is always available. The functionality of objects and methods can be tested in an ad hoc, dynamic manner using SQL statements. In many ways this is far more flexible for testing Java class functionality.

Scope and persistence
SQL variables are persistent only for the duration of the connection. This is unchanged from previous versions of Adaptive Server Anywhere, and is unaffected by whether the variable is a Java class or a native SQL data type. The persistence of Java classes is analogous to tables in a database: Tables exist in the database until you drop them, regardless of whether they hold data or even whether they are ever used. Java classes installed to a database are similar: they are available for use until you explicitly remove them with a REMOVE statement.

$ For more information on removing classes, see "REMOVE statement"
on page 589 of the book ASA Reference. A class method in an installed Java class can be called at any time from a SQL statement. You can execute the following statement anywhere you can execute SQL statements.
SELECT java.lang.Math.abs(-342)

A Java object is only available in two forms: as the value of a variable, or as a value in a table.

Java escape characters in SQL statements
In Java code, you can use escape characters to insert certain special characters into strings. Consider the following code, which inserts a new line and tab in front of a sentence containing an apostrophe. 537

The runtime environment for Java in the database
String str = "\n\t\This is an object\’s string literal";

Adaptive Server Anywhere permits the use of Java escape characters only when being used by Java classes. From within SQL, however, you must follow the rules that apply to strings in SQL. For example, to pass a string value to a field using a SQL statement, you could use the following statement, but the Java escape characters could not.
SET obj.str = ’\nThis is the object’’s string field’;

$ For more information on SQL string handling rules, see "Strings" on
page 224 of the book ASA Reference.

Keyword conflicts
SQL keywords can conflict with the names of Java classes, including API classes. This occurs when the name of a class, such as the Date class, which is a member of the java.util.* package, is referenced. SQL reserves the word Date for use as a keyword, even though it also the name of a Java class. When such ambiguities appear, you can use double quotes to identify that you are not using the word in question as the SQL reserved word. For example, the following SQL statement causes an error because Date is a keyword and SQL reserves its use.
-- This statement is incorrect CREATE VARIABLE dt java.util.Date

However the following two statements work correctly because the word Date is within quotation marks.
CREATE VARIABLE dt java.util."Date"; SET dt = NEW java.util."Date"(1997, 11, 22, 16, 11, 01)

The variable dt now contains the date: November 22, 1997, 4:11 p.m.

Use of import statements
It is common in a Java class declaration to include an import statement to access classes in another package. You can reference imported classes using unqualified class names. For example, you can reference the Stack class of the java.util package in two ways: ♦ ♦ 538 explicitly using the name java.util.Stack, or using the name Stack, and including the following import statement:
import java.util.*;

Chapter 17 Welcome to Java in the Database

Classes further up in the hierarchy must also be installed.

Aclass referenced by another class, either explicitly with a fully qualified name or implicitly using an import statement, must also be installed in the database. The import statement works as intended within compiled classes. However, within the Adaptive Server Anywhere runtime environment, no equivalent to the import statement exists. All class names used in SQL statements or stored procedures must be fully qualified. For example, to create a variable of type String, you would reference the class using the fully qualified name: java.lang.String.

Using the CLASSPATH variable
Sun’s Java runtime environment and the Sun JDK Java compiler use the CLASSPATH environment variable to locate classes referenced within Java code. A CLASSPATH variable provides the link between Java code and the actual file path or URL location of the classes being referenced. For example...
import java.io.*

... allows all the classes in the java.io package to be referenced without a fully qualified name. Only the class name is required in the following Java code to use classes from the java.io package. The CLASSPATH environment variable on the system where the Java class declaration is to be compiled must include the location of the java directory, the root of the java.io package. CLASSPATH ignored at runtime The CLASSPATH environment variable does not affect the Adaptive Server Anywhere runtime environment for Java during the execution of Java operations because the classes are stored in the database, instead of in external files or archives. The CLASSPATH variable can, however, be used to locate a file during the installation of classes. For example, the following statement installs a usercreated Java class to a database, but only specifies the name of the file, not its full path and name. (Note that this statement involves no Java operations.)
INSTALL JAVA NEW FROM FILE ’Invoice.class’

CLASSPATH used to install classes

If the file specified is in a directory or zip file specified by the CLASSPATH environmental variable, Adaptive Server Anywhere will successfully locate the file and install the class.

539

The runtime environment for Java in the database

Public fields
It is a common practice in object oriented programming to define class fields as private and make their values available only through public methods. Many of the examples used in this documentation render fields public to make examples more compact and easier to read. Using public fields in Adaptive Server Anywhere also offers a performance advantage over accessing public methods. The general convention followed in this documentation is that a user-created Java class designed for use in Adaptive Server Anywhere exposes its main values in its fields. Methods contain computational automation and logic that may act on these fields.

540

Chapter 17 Welcome to Java in the Database

A Java in the database exercise
This section is a primer for invoking Java operations on Java classes and objects using SQL statements. The examples use the Invoice class created in "A Java seminar" on page 523.
Case sensitivity

Java is case sensitive, so the portions of the following examples in this section pertaining to Java syntax are written using the correct case. SQL syntax is rendered in upper case.

A sample Java class
The examples in this section use the following class declaration.
Compiled code available

Adaptive Server Anywhere includes source code and compiled versions of all Java classes outlined in the documentation. You can compile and install the file Invoice.java into a database.
public class Invoice { // Fields public String lineItem1Description; public double lineItem1Cost; public String lineItem2Description; public double lineItem2Cost; // An instance method public double totalSum() { double runningsum; double taxfactor = 1 + Invoice.rateOfTaxation(); runningsum = lineItem1Cost + lineItem2Cost; runningsum = runningsum * taxfactor; return runningsum; } // A class method public static double rateOfTaxation() { double rate; rate = .15;

541

A Java in the database exercise

return rate; } }

Caution: use a Java-enabled database The following section assumes you are connected to a Java-enabled database. For more information, see "Java-enabling a database" on page 553.

Installing Java classes
Any Java class must be installed to a database before it can be used. You can install classes from Sybase Central or Interactive SQL.
v To install the Invoice class to the sample database from Sybase Central:

1 2

Start Sybase Central and choose Tools®Connect. On the Identification tab of the Connect dialog, select the ODBC Data Source Name option, and choose the ASA 7.0 Sample data source from the dropdown list. Click OK to connect to the sample database. Open the Java Objects folder and double-click Add Java Class or JAR. The Install a New Java Object wizard appears. In the wizard, select the Java Class File option and click Next. Use the Browse button to locate Invoice.class (in the jxmp subdirectory of your Adaptive Server Anywhere installation directory). Click Open to select the class file, and click Finish to exit the wizard.

3 4 5 6 7

v To install the Invoice class to the sample database from Interactive SQL:

1 2

Start Interactive SQL. On the Identification tab of the Connect dialog, select the ODBC Data Source Name option and choose the ASA 7.0 Sample data source from the dropdown list. Click OK to connect to the sample database. In the SQL Statements pane of the main Interactive SQL viewer, type the following:

3 4 542

Chapter 17 Welcome to Java in the Database
INSTALL JAVA NEW FROM FILE ’path\jxmp\Invoice.class’;

where path is your Adaptive Server Anywhere installation directory. Notes ♦ At this point no Java operations have taken place. The class has been installed into the database and is ready for use as the data type of a variable or column in a table. Changes made to the class file from now on are not automatically reflected in the copy of the class in the database. You must re-install the classes if you want the changes reflected.

$ For more information on installing classes, and for information on
updating an installed class, see "Installing Java classes into a database" on page 558.

Creating SQL variables of Java class type
The following statement creates a SQL variable named Inv of type Invoice, where Invoice is the Java class you installed to a database.
CREATE VARIABLE Inv Invoice;

Once you create a variable, it can only be assigned a value if its data type and declared data type are identical or if the valoue is a subclass of the declared data type. In this case, the variable Inv can only contain a reference to an object of type Invoice or a subclass of Invoice. Initially, the variable Inv is NULL because no value has been passed to it. You can use the following statement to identify the current value of the variable Inv.
SELECT IFNULL(Inv, ’No object referenced’, ’Variable not null: contains object reference’)

To assign a value to Inv, you must instatiate an instance of the Invoice class. The NEW keyword indicates a constructor is being invoked and an object reference is being returned.
SET Inv = NEW Invoice();

The Inv variable now has a reference to a Java object. To verify this, you can execute a number of select statements using the variable. The Inv variable should contain a reference to a Java object of type Invoice. Using this reference, you can access any of the object’s fields or invoke any of its methods.

543

A Java in the database exercise

Invoking Java operations
If a variable (or column value in a table) contains a reference to a Java object, then the fields of the object can be passed values and its methods can be invoked. For example, a variable of type Invoice (a user-created class) that contains a reference to an Invoice object will have four fields, the value of which can be set using SQL statements. Passing values to fields The following SQL statements set the field values for just such a variable.
SET SET SET SET Inv.lineItem1Description = ’Work boots’; Inv.lineItem1Cost = ’79.99’; Inv.lineItem2Description = ’Hay fork’; Inv.lineItem2Cost = ’37.49’;

Each line in the SQL statements above passes a value to a field in the Java object referenced by Inv. You can see this by performing a select statement against the variable. Any of the following SQL statements return the current value of a field in the Java object referenced by Inv.
SELECT SELECT SELECT SELECT Inv.lineItem1Description; Inv.lineItem1Cost; Inv.lineItem2Description; Inv.lineItem2Cost;

You can now use each of the above lines as an expression in other SQL statements. For example, you can execute the following SQL statement if you are currently connected to the sample database, asademo.db, and have executed the above SQL statements.
SELECT * FROM PRODUCT WHERE unit_price < Inv.lineItem2Cost;

Invoking methods

The Invoice class has one instance method, which you can invoke once an you create an Invoice object. The following SQL statement invokes the totalSum() method of the object referenced by the variable Inv. It returns the sum of the two cost fields plus the tax charged on this sum.
SELECT Inv.totalSum();

Calling methods versus referencing fields

Method names are always followed by parentheses, even when they take no arguments. Field names are not followed by parentheses. The totalSum() method takes no arguments but returns a value. The brackets are used because a Java operation is being invoked even though the method takes no arguments.

544

Chapter 17 Welcome to Java in the Database
Field access is faster than method invokation. Accessing a field does not require the Java VM to be invoked, while invoking a method requires the VM to execute the method. As indicated by the Invoice class definition outlined at the beginning of this section, the totalSum instance method makes use of the class method rateOfTaxation. You can access this class method directly from a SQL statement.
SELECT Invoice.rateOfTaxation();

Notice the name of the class is used, not the name of a variable containing a reference to an Invoice object. This is consistent with the way Java handles class methods, even though it is being used in a SQL statement. A class method can be invoked even if no object based on that class has been instantiated. Class methods do not require an instance of the class to work properly, but they can still be invoked on an object. The following SQL statement yields the same results as the previously executed SQL statement.
SELECT Inv.rateOfTaxation();

Saving Java objects in tables
When you install a class in a database, it is available as a new data type. Columns in a table can be of type Javaclass where Javaclass is the name of an installed public Java class. For example, using the Invoice class installed at the beginning of this section, you can execute the following SQL statement.
CREATE TABLE T1 ( ID int, JCol Invoice );

The column named JCol only accepts objects of type Invoice or one of its subclasses. There are at least two methods for creating a Java object and adding it to a table as the value of a column. The first method, creating a variable, was outlined in a previous section "Creating SQL variables of Java class type" on page 543. Assuming the variable Inv contains a reference to a Java object of type Invoice, the following SQL statement adds a row to the table T1.
INSERT INTO T1 VALUES( 1, Inv );

545

A Java in the database exercise
Once an object has been added to the table T1, you can issue select statements involving the fields and methods of the objects in the table. For example the following SQL statement returns the value of the field lineItem1Description for all the objects in the table T1 (right now, there should only be one object in the table).
SELECT ID, JCol.lineItem1Description FROM T1;

You can execute similar select statements involving other fields and methods of the object. A second method for creating a Java object and adding it to a table involves the following expression, which always creates a Java object and returns a reference to it:
NEW Javaclassname()

You can use this expression in a number of ways. For example, the following SQL statement creates a Java object and inserts it into the table T1.
INSERT INTO T1 VALUES ( 2, NEW Invoice() );

The following SQL statement verifies that these two objects have been saved as values of column JCol in the table T1.
SELECT ID, JCol.totalSum() FROM t1

The results of the JCol column (the second row returned by the above statement) should be 0, because the fields in that object have no values and the totalSum method is a calculation of those fields.

Returning an object using a query
You can also retrieve an object from a table with a Java class the same as the type of one of its columns. The following series of statements creates a new variable and passes a value (it can only contain an object reference where the object is of type Invoice). The object reference passed to the variable was generated using the table T1.
CREATE VARIABLE Inv2 Invoice; SET Inv2 = (select JCol from T1 where ID = 2); SET Inv2.lineItem1Description = ’Sweet feed’; SET Inv2.lineItem2Description = ’Drive belt’;

Take note that the value for the lineItem1Description field and lineItem2Description have been changed in the variable Inv2 but not in the table that was the source for the value of this variable. 546

Chapter 17 Welcome to Java in the Database
This is consistent with the way SQL variables are currently handled: the variable Inv contains a reference to a Java object. The value in the table that was the source of the variable’s reference is not altered until an UPDATE statement is executed.

547

A Java in the database exercise

548

C H A P T E R

1 8

Using Java in the Database

About this chapter Contents

This chapter describes how to add Java classes and objects to your database, and how to use these objects in a relational database.
Topic Overview of using Java Java-enabling a database Installing Java classes into a database Creating columns to hold Java objects Inserting, updating, and deleting Java objects Querying Java objects Comparing Java fields and objects Special features of Java classes in the database How Java objects are stored Java database design Using computed columns with Java classes Configuring memory for Java Page 550 553 558 563 565 570 572 575 580 583 586 589

Before you begin

To run the examples in this chapter, first run the file jdemo.sql, included in the jxmp subdirectory of your installation directory.

$ For full instructions, see "Setting up the Java examples" on page 550.

549

Overview of using Java

Overview of using Java
This chapter describes how to accomplish tasks using Java in the database, including the following: ♦ ♦ ♦ ♦
How to Java-enable a database

You need to follow certain steps to

enable your database to use Java.
Installing Java classes You need to install Java classes in a database to make them available for use in the server. Properties of Java columns Java database design

This section describes how columns with Java class data types fit into the relational model. This section provides tips for designing databases that use Java classes.

Setting up the Java examples
Many of the examples in this chapter require you to use a set of classes and tables added to the sample database. The tables hold the same information as tables of the same name in the sample database, but the user ID named jdba owns them. They use Java class data types instead of simple relational types to hold the information.
Sample tables designed for tutorial use only

The sample tables illustrate different Java features. They are not a recommendation for how to redesign your database. You should consider your own situation in evaluating where to incorporate Java data types and other features.
v To add Java classes and tables to the sample database using Interactive SQL:

1 2 3

Ensure that the database server has 8 Mb of cache available. Start Interactive SQL. On the Identification tab of the Connect dialog, select the ODBC Data Source Name option, and choose ASA 7.0 Sample from the dropdown list. Click OK when finished to connect to the sample database. In the SQL Statements pane of the main Interactive SQL viewer, type the following statement:
READ "path\jxmp\jdemo.sql"

4 5

550

Chapter 18 Using Java in the Database
where path is your Adaptive Server Anywhere installation directory. This runs the instructions in the jdemo.sql command file. The instructions may take some time to complete. You can view the jdemo.sql script using a text editor. It executes the following steps: 1 2 3 4 Installs the JDBCExamples class. Creates a user ID named JDBA with password SQL and DBA authority, and sets the current user to be JDBA. Installs a JAR file named asademo.jar. This file contains the class definitions used in the tables. Creates the following tables under the JDBA user ID: ♦ ♦ ♦ ♦ ♦ ♦ product contact customer employee sales_order sales_order_items

This is a subset of the tables in the sample database. 5 Adds the data from the standard tables of the same names into the Java tables. This step uses INSERT from SELECT statements. This step may take some time. Creates some indexes and foreign keys to add integrity constraints to the schema.
Tip

6

You can also start Interactive SQL and connect to the ASA 7.0 Sample data source from the command line:
dbisql -c "dsn=ASA 7.0 Sample"

Managing the runtime environment for Java
The runtime environment for Java consists of: ♦
The Sybase Java Virtual Machine Running within the database server, the Sybase Java Virtual Machine interprets and executes the compiled Java class files.

551

Overview of using Java

The runtime Java classes

When you create a database, a set of Java classes becomes available to the database. Java applications in the database require these runtime classes to work properly.

Management tasks for java

To provide a runtime environment for Java, you need to carry out the following tasks: ♦
Java-enable your database

This task involves ensuring the availability of built-in classes and the upgrading of the database to Version 7 standards.

$ For more information, see "Java-enabling a database" on page 553.

Install other classes your users need This task involves ensuring that classes other than the runtime classes are installed and up to date.

$ For more information, see "Installing Java classes into a database"
on page 558. ♦
Configuring your server You must configure your server to make the necessary memory available to run Java tasks.

$ For more information, see "Configuring memory for Java" on
page 589. Tools for managing Java You can carry out all these tasks from Sybase Central or from Interactive SQL.

552

Chapter 18 Using Java in the Database

Java-enabling a database
The Adaptive Server Anywhere Runtime environment for Java requires a Java VM and the Sybase runtime Java classes. The Java VM is always available as part of the database server, but you need to Java-enable a database for it to be able to use the runtime Java classes.
New databases are Java-enabled by default

By default, databases created with Adaptive Server Anywhere are Javaenabled. You can also Java-enable a database when you upgrade. Java is a single-hierarchy language, meaning that all classes you create or use eventually inherit from one class. This means the low-level classes (classes further up in the hierarchy) must be present before you can use higher-level classes. The base set of classes required to run Java applications are the runtime Java classes, or the Java API. When not to Javaenable a database Java-enabling a database adds many entries into the system tables. This adds to the size of the database and, more significantly, adds about 200K to the memory requirements for running the database, even if you do not use any Java functionality. If you are not going to use Java, and if you are running in a limited-memory environment, you may wish to not Java-enable your database.

The Sybase runtime Java classes
The following system zip files contain the Sybase runtime Java classes. The system zip files are in the Java subdirectory of your Adaptive Server Anywhere installation directory: ♦ ♦ ♦ Where the runtime classes are held
classes.zip This file, licensed from Sun Microsystems, contains the Sun Microsystem Java runtime classes. asajdbc.zip jdbcdrv.zip

This file contains Sybase internal JDBC driver classes. This file contains Sybase external JDBC driver classes.

The Sybase runtime Java classes are held on disk rather than stored in a database like other classes. When you Java-enable a database, you also update the system tables with a list of available classes from the system JAR files. You can then browse the class hierarchy from Sybase Central, but the classes themselves are not present in the database.

JAR files

The database stores runtime class names the under the following JAR files: 553

Java-enabling a database
♦ ♦ ♦ Installed packages
ASAJDBC

Class names from asajdbc.zip are held here. Class names from jdbcdrv.zip are held here.

ASAJDBCDRV ASASystem

Class names from classes.zip are held here.

These runtime classes include the following packages: ♦
java

Packages stored here include the supported Java runtime classes from Sun Microsystems. For a list of the supported Java runtime classes, see "Supported Java packages" on page 288 of the book ASA Reference. Packages stored here provide server-side JDBC support.

♦ ♦ ♦

com.sybase sun

Sun Microsystems provides the packages stored here.

sybase.sql

Packages stored here are part of the Sybase server-side JDBC support.

Caution: do not install classes from another version of Sun’s JDK Classes in Sun’s JDK share names with the Sybase runtime Java classes that must be installed in any database intended to execute Java operations.

You must not replace the classes.zip file included with Adaptive Server Anywhere. Using another version of these classes could cause compatibility problems with the Sybase Java Virtual Machine. You must only Java-enable a database using the methods outlined in this section.

Ways of Java-enabling a database
You can Java-enable databases when you create them, when you upgrade them, or at a later time. Creating databases You can create a Java-enabled database using: ♦ the CREATE DATABASE statement. For details of the syntax, see "CREATE DATABASE statement" on page 427 of the book ASA Reference. the dbinit command-line utility. For details, see "The dbinit commandline utility" on page 99 of the book ASA Reference. Sybase Central. For details, see "Creating a database" on page 115.

♦ ♦ Upgrading databases

You can upgrade a Version 5 database to a Java-enabled Version 7 database using:

554

Chapter 18 Using Java in the Database
♦ the ALTER DATABASE statement. For details of the syntax, see "ALTER DATABASE statement" on page 383 of the book ASA Reference. the dbupgrad.exe upgrade utility. For details, see "The dbupgrad command-line utility" on page 145 of the book ASA Reference.

If you choose not to install the Sybase runtime Java classes in a database, all database operations not involving Java operations remain fully functional and work as expected.

New databases and Java
By default, Adaptive Server Anywhere installs Sybase runtime Java classes each time you create a database, thereby making all new databases Javaenabled. The installation of these classes, however, is optional, and controlled by the method you use to create the database. CREATE DATABASE options The CREATE DATABASE SQL statement has an option called JAVA. To Java-enable a database, you can set the option to ON.To disable Java, set the option to OFF. This option is is set to ON by default. For example, the following statement creates a Java-enabled database file named temp.db:
CREATE DATABASE ’c:\\sybase\\asa7\\temp’

The following statement creates a database file named temp2.db, which does not support Java.
CREATE DATABASE ’c:\\sybase\\asa7\\temp2’ JAVA OFF

Database initialization utility

You can create databases using the dbinit.exe command-line database initialization utility. The utility has a –j switch that controls whether or not to install the Sybase runtime Java classes in the newly-created database. Using the –j switch prevents the Sybase runtime Java classes from being installed. Not using the switch installs the Java classes by default. The same option is available when creating databases using Sybase Central.

Upgrading databases and Java
You can upgrade existing databases created with Sybase SQL Anywhere Version 5 or earlier using the command-line database upgrade utility or from Sybase Central. 555

Java-enabling a database

Database upgrade utility

You can upgrade databases to Adaptive Server Anywhere Version 7 standards using the dbupgrad.exe command-line utility. Using the –j switch prevents the installation of Sybase runtime Java classes. Not using the switch installs the Java classes by default.

Java-enabling a Version 7 database
If you have created a Version 7 database, or upgraded a database to Version 7 standards, but have chosen not to Java-enable the database, you can add the necessary Java classes at a later date, using either Sybase Central or Interactive SQL.
v To add the Java runtime classes to a database (Sybase Central):

1 2 3 4

Connect to the database from Sybase Central as a user with DBA authority. Open the Java Objects folder. Double-click Add Base Java Classes. If you cannot see this icon, it means that your database already has the Java runtime classes installed. Follow the instructions in the wizard.

v To add the Java runtime classes to a database (SQL):

1 2

Connect to the database from Interactive SQL as a user with DBA authority. Run the script instjava.sql from the scripts directory:
read "path/scripts/instjava.sql"

where path is the name of your Adaptive Server Anywhere installation directory.

Using Sybase Central to Java-enable a database
You can use Sybase Central to create and upgrade databases using wizards. During the creation or upgrade of a database, the wizard prompts you to choose whether or not you have the Sybase runtime Java classes installed. By default, this option Java-enables the database. Using Sybase Central, you can create or upgrade a database by choosing: ♦ Create database from the Utilities folder, or

556

Chapter 18 Using Java in the Database
♦ Upgrade database from the Utilities folder to upgrade a Version 5 or Version 4 database to a Version 7 database with Java capabilities.

557

Installing Java classes into a database

Installing Java classes into a database
Before you install a Java class into a database, you must compile it. You can install Java classes into a database as: ♦ ♦
A single class You can install a single class into a database from a compiled class file. Class files typically have extension .class. A jar

You can install a set of classes all at once if they are in either a compressed or uncompressed jar file. JAR files typically have the extension .jar or .zip. Adaptive Server Anywhere supports all compressed jar files created with the Sun jar utility, and some other jar compression schemes as well.

This section describes how to install Java classes once you have compiled them. You must have DBA authority to install a class or jar.

Creating a class
Although the details of each step may differ depending on whether you are using a Java development tool such as Sybase PowerJ, the steps involved in creating your own class generally include the following:
v To create a class:

1

Define your class

Write the Java code that defines your class. If you are using the Sun Java SDK then you can use a text editor. If you are using a development tool such as Sybase PowerJ, the development tool provides instructions.
Use only supported classes

If your class uses any runtime Java classes, make certain they are among the list of supported classes as listed in "Supported Java packages" on page 288 of the book ASA Reference. User classes must be 100% Java. Native methods are not allowed. 2
Name and save your class

Save your class declaration (Java code) in a file with the extension .java. Make certain the name of the file is the same as the name of the class and that the case of both names is identical. For example, a class called Utility should be saved in a file called Utility.java.

558

Chapter 18 Using Java in the Database
3
Compile your class This step turns your class declaration containing Java code into a new, separate file containing byte code. The name of the new file is the same as the Java code file but has an extension of .class. You can run a compiled Java class in a Java runtime environment, regardless of the platform you compiled it on or the operating system of the runtime environment.

The Sun JDK contains a Java compiler, Javac.exe.
Java-enabled databases only

You can install any compiled Java class file in a database. However, Java operations using an installed class can only take place if the database has been Java-enabled as described in "Java-enabling a database" on page 553.

Installing a class
To make your Java class available within the database, you install the class into the database either from Sybase Central, or using the INSTALL statement from Interactive SQL or other application. You must know the path and file name of the class you wish to install. You require DBA authority to install a class.
v To install a class (Sybase Central):

1 2 3 4

Connect to a database with DBA authority. Open the Java Objects folder for the database. Double-click Add Java Class or JAR. Follow the instructions in the wizard.

v To install a class (SQL):

1 2

Connect to a database with DBA authority. Execute the following statement:
INSTALL JAVA NEW FROM FILE ’path\\ClassName.class’

where path is the directory where the class file is, and ClassName.class is the name of the class file. The double backslash ensures that the backslash is not treated as an escape character. 559

Installing Java classes into a database
For example, to install a class in a file named Utility.class, held in the directory c:\source, you would enter the following statement:
INSTALL JAVA NEW FROM FILE ’c:\\source\\Utility.class’

If you use a relative path, it must be relative to the current working directory of the database server.

$ For more information, see "INSTALL statement" on page 556 of the
book ASA Reference, and "Deleting Java objects, classes, and JAR files" on page 569.

Installing a JAR
It is useful and common practice to collect sets of related classes together in packages, and to store one or more packages in a JAR file. For information on JAR files and packages, see the accompanying online book, Thinking in Java, or another book on programming in Java. You install a JAR file the same way as you install a class file. A JAR file can have the extension JAR or ZIP. Each JAR file must have a name in the database. Usually, you use the same name as the JAR file, without the extension. For example, if you install a JAR file named myjar.zip, you would generally give it a JAR name of myjar.
v To install a JAR (Sybase Central):

1 2 3 4

Connect to a database with DBA authority. Open the Java Objects folder for the database. Double-click Add Java Class or JAR. Follow the instructions in the wizard.

v To install a JAR (SQL):

1 2

Connect to a database with DBA authority. Enter the following statement:
INSTALL JAVA NEW JAR ’jarname’ FROM FILE ’path\\JarName.jar’

$ For more information, see "INSTALL statement" on page 556 of the
book ASA Reference, and "Deleting Java objects, classes, and JAR files" on page 569.

560

Chapter 18 Using Java in the Database

Updating classes and JARs
You can update classes and JAR files using Sybase Central or by entering an INSTALL statement in Interactive SQL or some other client application. To update a class or JAR, you must have DBA authority and a newer version of the compiled class file or JAR file available in a file on disk. Existing Java objects and updated classes You may have instances of a Java class stored as Java objects in your database, or as values in a column that uses the class as its data type. Despite updating the class, these old values will still be available, even if the fields and methods stored in the tables are incompatible with the new class definition. Any new rows you insert, however, need to be compatible with the new definition. When updated classes take effect Only new connections established after installing the class, or which use the class for the first time after installing the class, use the new definition. Once the Virtual Machine loads a class definition, it stays in memory until the connection closes. If you have been using a Java class or objects based on a class in the current connection, you need to disconnect and reconnect to use the new class definition.

$ To understand why the updated classes take effect in this manner, you need to know a little about how the VM works. For information, see "Configuring memory for Java" on page 589.
Objects stored in serialized form Java objects can use the updated class definition because they are stored in serialized form. The serialization format, designed specifically for the database, is not the Sun Microsystems serialization format. The internal Sybase VM carries out all serialization and deserialization , so there are no compatibility issues.
v To update a class or JAR (Sybase Central):

1 2 3 4 5

Connect to a database with DBA authority. Open the Java Objects folder. Locate the class or JAR file you wish to update. Right-click the class or JAR file and choose Update from the popup menu. In the resulting dialog, specify the name and location of the class or JAR file to be updated. You can click Browse to search for it.

561

Installing Java classes into a database

Tip

You can also update a Java class or JAR file by clicking Update Now on the General tab of its property sheet.
v To update a class or JAR (SQL):

1 2

Connect to a database with DBA authority. Execute the following statement:
INSTALL JAVA UPDATE [ JAR ’jarname’ ] FROM FILE ’filename’

If you are updating a JAR, you must enter the name by which the JAR is known in the database.

$ See also
♦ ♦ ♦ ♦ "INSTALL statement" on page 556 of the book ASA Reference "Update Java Class dialog" on page 1041 "Update JAR dialog" on page 1041 "Java Objects properties" on page 1089

562

Chapter 18 Using Java in the Database

Creating columns to hold Java objects
This section describes how columns of Java class data types fit into the standard SQL framework.

Creating columns with Java data types
You can use any installed Java class as a data type. You must use the fully qualified name for the data type. For example, the following CREATE TABLE statement includes a column that has columns of Java data types asademo.Name and asademo.ContactInfo. Here, Name and ContactInfo are classes within the asademo package.
CREATE TABLE jdba.customer ( id integer NOT NULL, company_name CHAR(35) NOT NULL, JName asademo.Name NOT NULL, JContactInfo asademo.ContactInfo NOT NULL, PRIMARY KEY (id) )

Case sensitivity

Unlike other SQL data types, Java data types are case sensitive. You must supply the proper case of all parts of the data type.

Using defaults and NULL on Java columns
You can use defaults on Java columns, and Java columns can hold NULL entries.
Java columns and defaults Columns can have as default values any function of the proper data type, or any preset default. You can use any function of the proper data type (for example, of the same class as the column) as a default value for Java columns. Java columns and NULL Java columns can allow NULL. If a nullable column with Java data type has no default value, the column contains NULL.

If a Java value is not set, it has a Java null value. This Java null maps onto the SQL NULL, and you can use the IS NULL and IS NOT NULL search conditions against the values. For example, suppose the description of a Product Java object in a column named JProd was not set, you can query all products with non-null values for the description as follows:
SELECT *

563

Creating columns to hold Java objects
FROM product WHERE JProd>>description IS NULL

564

Chapter 18 Using Java in the Database

Inserting, updating, and deleting Java objects
This section describes how the standard SQL data manipulation statements apply to Java columns. Throughout the section, concrete examples based on the Product table of the sample database and a class named Product, illustrate points. You should first look at the file Product.java held in the jxmp\asademo subdirectory of your installation directory. Create the Java sample tables The examples in this section assume that you have added the Java tables to the sample database, and that you are connected as user ID jDBA with password SQL.

$ For further instructions, see "Setting up the Java examples" on
page 550.

A sample class
This section describes a class that is used in examples throughout the following sections. The Product.java class definition, included in the jxmp\asademo directory under your installation directory, is reproduced in part below:
package asademo; public class Product implements java.io.Serializable { // public fields public String name ; public String description ; public String size ; public String color; public int quantity ; public java.math.BigDecimal unit_price ; // Default constructor Product () { unit_price = new java.math.BigDecimal( 10.00 ); name = "Unknown"; size = "One size fits all"; } // Constructor using all available arguments Product ( String inColor, String inDescription, String inName, int inQuantity,

565

Inserting, updating, and deleting Java objects
String inSize, java.math.BigDecimal inUnit_price ) { color = inColor; description = inDescription; name = inName; quantity = inQuantity; size = inSize; unit_price=inUnit_price; } public String toString() { return size + " " + name + ": " + unit_price.toString(); }

Notes

The Product class has several public fields that correspond to some of the columns of the dba.Product table that will be collected together in this class. The toString method is provided for convenience. When you include an object name in a select-list, the toString method is executed and its return string displayed. Some methods are provided to set and get the fields. It is common to use such methods in object-oriented programming rather than to address the fields directly. Here the fields are public for convenience in tutorials.

Inserting Java objects
When you INSERT a row in a table that has a Java column, you need to insert a Java object into the Java column. You can insert a Java object in two ways: from SQL or from other Java classes running inside the database, using JDBC.

Inserting a Java object from SQL
You can insert a Java object using a constructor, or you can use SQL variables to build up a Java object before inserting it. Inserting an object using a constructor When you insert a value into a column that has a Java class data type, you are inserting a Java object. To insert an object with the proper set of properties, the new object must have proper values for any public fields, and you will want to call any methods that set private fields.

566

Chapter 18 Using Java in the Database
v To insert a Java object:

INSERT a new instance of the Product class into the table product as follows:
INSERT INTO product ( ID, JProd ) VALUES ( 702, NEW asademo.Product() )

You can run this example against the sample database from the user ID jdba once the jdemo.sql script has been run. The NEW keyword invokes the default constructor for the Product class in the asademo package. Inserting an object from a SQL variable You can also set the values of the fields of the object individually, as opposed to through the constructor, in a SQL variable of the proper class.
v To insert a Java object using SQL variables:

1 2 3

Create a SQL variable of the Java class type:
CREATE VARIABLE ProductVar asademo.Product

Assign a new object to the variable, using the class constructor:
SET ProductVar = NEW asademo.Product()

Assign values to the fields of the object, where required:
SET SET SET SET SET SET ProductVar>>color = ’Black’; ProductVar>>description = ’Steel tipped boots’; ProductVar>>name = ’Work boots’; ProductVar>>quantity = 40; ProductVar>>size = ’Extra Large’; ProductVar>>unit_price = 79.99;

4

Insert the variable into the table:
INSERT INTO Product ( id, JProd ) VALUES ( 800, ProductVar )

5

Check that the value is inserted:
SELECT * FROM product WHERE id=800

6

Undo the changes you have made in this exercise:
ROLLBACK

567

Inserting, updating, and deleting Java objects
The use of SQL variables is typical of stored procedures and other uses of SQL to build programming logic into the database. Java provides a more powerful way of accomplishing this task. You can use server-side Java classes together with JDBC to insert objects into tables.

Inserting an object from Java
You can insert an object into a table using a JDBC prepared statement. A prepared statement uses placeholders for variables. You can then use the setObject method of the PreparedStatement object. You can use prepared statements to insert objects from either client-side or server-side JDBC.

$ For more information on using prepared statements to work with
objects, see "Inserting and retrieving objects" on page 610.

Updating Java objects
You may wish to update a Java column value in either of the following ways: ♦ ♦ Updating the entire object Update the entire object. Update some of the fields of the object.

You can update the object in much the same way as you insert objects: ♦ From SQL, you can use a constructor to update the object to a new object as the constructor creates it. You can then update individual fields if you need to. From SQL, you can use a SQL variable to hold the object you need, and then update the row to hold the variable. From JDBC, you can use a prepared statement and the PreparedStatement.setObject method.

♦ ♦ Updating fields of the object

Individual fields of an object have data types that correspond to SQL data types, using the SQL to Java data type mapping described in "Java / SQL data type conversion" on page 294 of the book ASA Reference. You can update individual fields using a standard UPDATE statement:
UPDATE Product SET JProd.unit_price = 16.00 WHERE ID = 302

In the initial release of Java in the database, it was necessary to use a special function (EVALUATE) to carry out updates. This is no longer necessary. 568

Chapter 18 Using Java in the Database
To update a Java field, the Java data type of the field must map to a SQL type, the expression on the right hand side of the SET clause must match this type. You may need to use the CAST function to cast the data types appropriate.

$ For information on data type mappings between Java and SQL, see
"Java / SQL data type conversion" on page 294 of the book ASA Reference. Using set methods It is common practice in Java programming not to address fields directly, but to use methods to get and set the value. It is also common practice for these methods to return void. You can use set methods in SQL to update a column:
UPDATE jdba.Product SET JProd.setName( ’Tank Top’) WHERE id=302

Using methods is slower than addressing the field directly, because the Java VM must run.

$ For more information, see "Return value of methods returning void" on
page 576.

Deleting Java objects, classes, and JAR files
Deleting rows containing Java objects is no different than deleting other rows. The WHERE clause in the DELETE statement can include Java objects or Java fields and methods. For more information, see "DELETE statement" on page 496 of the book ASA Reference. Using Sybase Central, you can also delete an entire Java class or JAR file.
v To delete a Java class or JAR file (Sybase Central):

1 2 3

Open the Java Objects folder. Locate the class or JAR you would like to delete. Right-click the class or JAR file and choose Delete from the popup menu.

$ See also
♦ ♦ "Installing a class" on page 559 "Installing a JAR" on page 560

569

Querying Java objects

Querying Java objects
You may wish to retrieve a Java column value in either of the following ways: ♦ ♦ Retrieving the entire object Retrieve the entire object. Retrieve some of the fields of the object.

From SQL, you can create a variable of the appropriate type, and select the value from the object into that variable. However, the obvious place in which you may wish to make use of the entire object is in a Java application. You can retrieve an object into a server-side Java class using the getObject method of the ResultSet of a query. You can also retrieve an object to a client-side Java application.

$ For a description of retrieving objects using JDBC, see "Queries using
JDBC" on page 607. Retrieving fields of the object Individual fields of an object have data types that correspond to SQL data types, using the SQL to Java data type mapping described in "Java / SQL data type conversion" on page 294 of the book ASA Reference. ♦ You can retrieve individual fields by including them in the select-list of a query, as in the following simple example:
SELECT JProd>>unit_price FROM product WHERE ID = 400

If you use methods to set and get the values of your fields, as is common in object oriented programming, you can include a getField method in your query:
SELECT JProd>>getName() FROM Product WHERE ID = 401

$ For information on using objects in the WHERE clause and other issues
in comparing objects, see "Comparing Java fields and objects" on page 572.
Performance tip

Getting a field directly is faster than invoking a method that gets the field, because method invocations require starting the Java VM. The results of SELECT columnname You can list the column name in a query select list, as in the following query:
SELECT JProd FROM jdba.product

570

Chapter 18 Using Java in the Database
This query returns the Sun serialization of the object to the client application. When you execute a query that retrieves an object in Interactive SQL, it displays the return value of the object’s toString method. For the Product class, the toString method lists, in one string, the size, name, and unit price of the object. The results of the query are as follows:
JProd Small Tee Shirt: 9.00 Medium Tee Shirt: 14.00 One size fits all Tee Shirt: 14.00 One size fits all Baseball Cap: 9.00 One size fits all Baseball Cap: 10.00 One size fits all Visor: 7.00 One size fits all Visor: 7.00 Large Sweatshirt: 24.00 Large Sweatshirt: 24.00 Medium Shorts: 15.00

571

Comparing Java fields and objects

Comparing Java fields and objects
Public Java classes are domains with much more richness than traditional SQL domains. This raises issues about how Java columns behave in a relational database, compared to columns based on traditional SQL data types. In particular, the issue of how objects are compared has implications for the following: ♦ ♦ ♦ ♦ Ways of comparing Java objects Queries with an ORDER BY clause, a GROUP BY clause, a DISTINCT keyword, or using an aggregate function. Statements that use equality or inequality comparison conditions Indexes and unique columns Primary and foreign key columns.

Sorting and ordering rows, whether in a query or in an index, implies a comparison between values on each row. If you have a Java column, you can carry out comparisons in the following ways: ♦
Compare on a public field You can compare on a public field in the same way you compare on a regular row. For example, you could execute the following query: SELECT name, JProd.unit_price FROM Product ORDER BY JProd.unit_price

You can use this kind of comparison in queries, but not for indexes and key columns. ♦
Compare using a compareTo method You can compare Java objects that have implemented a compareTo method. The Product class on which the JProd column is based has a compareTo method that compares objects based on the unit_price field. This permits the following query: SELECT name, JProd.unit_price FROM Product ORDER BY JProd

The comparison needed for the ORDER BY clause is automatically carried out based on the compareTo method.

572

Chapter 18 Using Java in the Database

Comparing Java objects
To compare two objects of the same type, you must implement a compareTo method: ♦ For columns of Java data types to be used as primary keys, indexes, or as unique columns, the column class must implement a compareTo method. To use ORDER BY, GROUP BY, or DISTINCT clauses in a query, you must be comparing the values of the column. The column class must have a compareTo method for any of these clauses to be valid. Functions that employ comparisons, such as MAX and MIN, can only be used on a Java classes with a compareTo method.

♦ Requirements of the compareTo method

The compareTo method must have the following properties: ♦ ♦
Scope

The method must be visible externally, and so should be a public method.

Arguments The method takes a single argument, which is an object of the current type. The current object is compared to the supplied object. For example, Product.compareTo has the following argument: compareTo( Product anotherProduct )

The method compares the anotherProduct object, of type Product, to the current object. ♦
Return values

The compareTo method must return an int data type, with the following meanings: ♦
Negative integer

The current object is less than the supplied object. It is recommended that you return -1 for this case, for compatibility with compareTo methods in base Java classes. The current object has the same value as the supplied object.

♦ ♦

Zero

Positive integer

The current object is greater than the supplied object. It is recommended that you return 1 for this case, for compatibility with compareTo methods in base Java classes.

Example

The Product class installed into the sample database with the example classes has a compareTo method as follows:
public int compareTo( Product anotherProduct ) { // Compare first on the basis of price // and then on the basis of toString() int lVal = unit_price.intValue(); int rVal = anotherProduct.unit_price.intValue(); if ( lVal > rVal ) { return 1;

573

Comparing Java fields and objects
} else if (lVal < rVal ) { return -1; } else { return toString().compareTo( anotherProduct.toString() );{ } } }

This method compares the unit price of each object. If the unit prices are the same, then the names are compared (using Java string comparison, not the database string comparison). Only if both the unit price and the name are the same are the two objects considered the same when comparing. Make toString and compareTo compatible When you include a Java column in the select list of a query, and execute it in Interactive SQL, the value of the toString method is displayed. When comparing columns, the compareTo method is used. If the toString and compareTo methods are not implemented consistently with each other, you can get inappropriate results such as DISTINCT queries that appear to return duplicate rows. For example, suppose the Product class in the sample database had a toString method that returned the product name, and a compareTo method based on the price. Then the following query, executed in Interactive SQL, would display duplicate values:
SELECT DISTINCT JProd FROM product JProd Tee Shirt Tee Shirt Baseball Cap Visor Sweatshirt Shorts

Here, the returned value being displayed is determined by toString. The DISTINCT keyword eliminates duplicates as determined by compareTo. As these have been implemented in ways that are not related to each other, duplicate rows appear to have been returned.

574

Chapter 18 Using Java in the Database

Special features of Java classes in the database
This section describes features of Java classes when used in the database.

Supported classes
You cannot use all classes from the JDK. The runtime Java classes available for use in the database server belong to a subset of the Java API.

$ For a list of all supported packages, see "Supported Java packages" on
page 288 of the book ASA Reference.

Using threads in Java applications
You can use multiple threads in a Java application, by using features of the java.lang.Thread package. Each Java thread is an engine thread, and comes from the number of threads permitted by the -gn command-line option database server command-line option. You can synchronize, suspend, resume, interrupt, or stop threads in Java applications.

$ For information on database server threads, see "–gn command-line
option" on page 28 of the book ASA Reference. Serialization of JDBC calls All calls to the server-side JDBC driver are serialized, such that only one thread is actively executing JDBC at any one time.

Procedure Not Found error
If you supply an incorrect number of arguments when calling a Java method, or if you use an incorrect data type, the server responds with a Procedure Not Found error. You should check the number and type of arguments.

$ For a list of type conversions between SQL and Java, see "Java / SQL
data type conversion" on page 294 of the book ASA Reference.

The main method
You typically start Java applications (outside the database) by running the Java VM on a class that has a main method.

575

Special features of Java classes in the database
For example, the JDBCExamples class in the jxmp subdirectory of the Adaptive Server Anywhere installation directory has a main method. When you execute the class from the command line using a command such as the following,
java JDBCExamples

it is the main method that executes.

$ For information on how to run the JDBCExamples class, see "Establishing JDBC connections" on page 597.
The main method must be declared as follows:
public static void main( java.lang.String[] args ){ ... }

You can call the main method of classes installed into a database from SQL. Each argument you provide becomes an element of the String array, and so must be a CHAR or VARCHAR data type, or a literal string. Example The following class contains a main method, which writes out the arguments in reverse order:
public class ReverseWrite { public static void main( String[] args ){ int i: for( i = args.length; i > 0 ; i-- ){ System.out.print( args[ i-1 ] ); } } }

You can execute this method from SQL as follows:
call ReverseWrite.main( ’ one’, ’ two’, ’three’ )

The database server window displays the output:
three two one

Return value of methods returning void
You can use Java methods in SQL statements wherever you can use an expression. You must ensure that the Java method return data type maps to the appropriate SQL data type.

$ For a list of Java/SQL data type mappings, see "Java / SQL data type
conversion" on page 294 of the book ASA Reference.

576

Chapter 18 Using Java in the Database
When a method returns void, however, the value this is returned to SQL; that is, the object itself. The feature only affects calls made from SQL, not from Java. This feature is particularly useful in UPDATE statements, where set methods commonly return void. You can use the following UPDATE statement in the sample database:
update jdba.product set JProd = JProd.setName(’Tank Top’) where id=302

The setName method returns void, and so implicitly returns the product object to SQL.

Returning result sets from Java methods
This section describes how to make result sets available from Java methods. You must write a Java method that returns a result set to the calling environment, and wrap this method in a SQL stored procedure declared to be EXTERNAL NAME of LANGUAGE JAVA.
v To return result sets from a Java method:

1 2

Ensure that the Java method is declared as public and static, in a public class. For each result set you expect the method to return, ensure that the method has a parameter of type java.sql.ResultSet[]. These result-set parameters must all occur at the end of the parameter list. In the method, first create an instance of java.sql.ResultSet and then assign it to one of the ResultSet[] parameters. Create a SQL stored procedure of type EXTERNAL NAME LANGUAGE JAVA. This type of procedure is a wrapper around a Java method. You can use a cursor on the SQL procedure result set in the same way as any other procedure that returns result sets.

3 4

$ For information on the syntax for stored procedures that are
wrappers for Java methods, see "CREATE PROCEDURE statement" on page 453 of the book ASA Reference. Example The following simple class has a single method, which executes a query and passes the result set back to the calling environment.
import java.sql.*; public class MyResultSet { public static void return_rset( ResultSet[] rset1 )

577

Special features of Java classes in the database
throws SQLException { Connection conn = DriverManager.getConnection( "jdbc:default:connection" ); Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery ( "SELECT CAST( JName.lastName " + "AS CHAR( 50 ) )" + "FROM jdba.contact " ); rset1[0] = rset; } }

You can expose the result set using a CREATE PROCEDURE statement that indicates the number of result sets returned from the procedure and the signature of the Java method. A CREATE PROCEDURE statement indicating a result set could be defined as follows:
CREATE PROCEDURE result_set() DYNAMIC RESULT SETS 1 EXTERNAL NAME ’MyResultSet.return_rset ([Ljava/sql/ResultSet;)V’ LANGUAGE JAVA

You can open a cursor on this procedure just as you can with any ASA procedure returning result sets. The string (Ljava/sql/ResultSet;)V is a Java method signature, which is a compact character representation of the number and type of the parameters and return value.

$ For more information about Java method signatures, see "CREATE
PROCEDURE statement" on page 453 of the book ASA Reference.

Returning values from Java via stored procedures
You can use stored procedures created using the EXTERNAL NAME LANGUAGE JAVA as wrappers around Java methods. This section describes how to write your Java method to exploit OUT or INOUT parameters in the stored procedure. Java does not have explicit support for INOUT or OUT parameters. Instead, you can use an array of the parameter. For example, to use an integer OUT parameter, create an array of exactly one integer:
public class TestClass { public static boolean testOut( int[] param ){ param[0] = 123; return true;

578

Chapter 18 Using Java in the Database
} }

The following procedure uses the testOut method:
CREATE PROCEDURE sp_testOut ( OUT p INTEGER ) EXTERNAL NAME ’TestClass/testOut ([I)Z’ LANGUAGE JAVA

The string ([I)Z is a Java method signature, indicating that the method has a single parameter, which is an array of integers, and returns a boolean. You must define the method so that the method parameter you wish to use as an OUT or INOUT parameter is an array of a Java data type that corresponds to the SQL data type of the OUT or INOUT parameter.

$ For details of the syntax, including the method signature, see "CREATE
PROCEDURE statement" on page 453 of the book ASA Reference.

$ For more information, see "Java / SQL data type conversion" on
page 294 of the book ASA Reference.

579

How Java objects are stored

How Java objects are stored
Java values are stored in serialized form. This means that each row contains the following information: ♦ ♦ ♦ ♦ A version identifier. An identifier for the class (or subclass) that is stored. The values of non-static, non-transient fields in the class. Other overhead information.

The class definition is not stored for each row. Instead, the identifier provides a reference to the class definition, which is held only once. You can use Java objects without knowing the details of how these pieces work, but storage methods for these objects do have some implications for performance and so information follows. Notes ♦
Disk space The overhead per row is 10 to 15 bytes. If the class has a single variable, then the storage required for the overhead can be similar to the amount needed for the variable itself. If the class has many variables, the overhead is negligible. Performance

Any time you insert or update a Java value, the Java VM needs to serialize it. Any time a Java value is retrieved in a query, it needs to be deserialized by the VM. This can amount to a significant performance penalty. You can avoid the performance penalty for queries using computed columns.

Indexing

Indexes on Java columns will not be very selective, and will not provide the performance benefits associated with indexes on simple SQL data types.

If a class has a readObject or writeObject method, these are called when deserializing or serializing the instance. Using a readObject or writeObject method can impact performance, because the Java VM is being invoked.
Serilalization

Java objects and class versions
Java objects stored in the database are persistent; that is, they exist even when no code is running. This means that you could carry out the following sequence of actions: 1 580 Install a class.

Chapter 18 Using Java in the Database
2 3 4 Create a table using that class as the data type for a column. Insert rows into the table. Install a new version of the class.

How will the existing rows work with the new version of the class? Accessing rows when a class is updated Adaptive Server Anywhere provides a form of class versioning to allow the new class to work with the old rows. The rules for accessing these older values are as follows: ♦ ♦ If a serializable field is in the old version of the class, but is either missing or not serializable in the new version, the field is ignored. If a serializable field is in the new version of the class, but was either missing or not serializable in the old version, the field is initialized to a default value. The default value is 0 for primitive types, false for Boolean values, and NULL for object references. If there was a superclass of the old version that is not a superclass of the new version, the data for that superclass is ignored. If there is a superclass of the new version that was not a superclass of the old version, the data for that superclass is initialized to default values. If a serializable field changes type between the older version and the newer version, the field is initialized to a default values. Type conversions are not supported; this is consistent with Sun Microsystems serialization.

♦ ♦

When objects are inaccessible Moving objects across databases

A serialized object is unaccessible if the class of the object or any of its superclasses has been removed from the database, at any time. This behavior is consistent with Sun Microsystems serialization. These changes make cross database transfer of objects possible even when the versions of classes differ. Cross database transfer can occur as follows: ♦ ♦ ♦ Objects are replicated to a remote database. A table of objects is unloaded and reloaded into another database. A log file containing objects is translated and applied against another database.

When the new class is used

Each connection’s VM loads the class definition for each class the first time that class is used. When you INSTALL a class, the VM on your connection is implicitly restarted. Therefore, you have immediate access to the new class.

581

How Java objects are stored
For connections other than the one that carries out the INSTALL, the new class loads the next time a VM accesses the class for the first time. If the class is already loaded by a VM, that connection does not see the new class until the VM is restarted for that connection (for example, with a STOP JAVA and START JAVA).

582

Chapter 18 Using Java in the Database

Java database design
There is a large body of theory and practical experience available to help you design a relational database. You can find descriptions Entity-Relationship design and other approaches not only in introductory form (see "Designing Your Database" on page 333) but also in more advanced books. No comparable body of theory and practice to develop object-relational databases exists, and this certainly applies to Java-relational databases. Here we offer some suggestions for how to use Java to enhance the practical usefulness of relational databases.

Entities and attributes in relational and object-oriented data
In relational database design, each table describes an entity. For example, in the sample database there are tables named Employee, Customer, Sales_order, and Department. The attributes of these entities become the columns of the tables: employee addresses, customer identification numbers, sales order dates, and so on. Each row of the table may be considered as a separate instance of the entitya specific employee, sales order, or department. In object-oriented programming, each class describes an entity, and the methods and fields of that class describe the attributes of the entity. Each instance of the class (each object) holds a separate instance of the entity. It may seem unnatural, therefore, for relational columns to be based on Java classes. A more natural correspondence may seem to be between table and class.

Entities and attributes in the real world
The distinction between entity and attribute may sound clear, but a little reflection shows that it is commonly not at all clear in practice: ♦ ♦ An address may be seen as an attribute of a customer, but an address is also an entity, with its own attributes of street, city, and so on. A price may be seen as an attribute of a product, but may also be seen as an entity, with attributes of amount and currency.

The utility of the object-relational database lies in exactly the fact that there are two ways of expressing entities. You can express some entities as tables, and some entities as classes in a table. The next section describes an example. 583

Java database design

Relational database limitations
Consider an insurance company wishing to keep track of its customers. A customer may be considered as an entity, so it is natural to construct a single table to hold all customers of the company. However, insurance companies handle several kinds of customer. They handle policy holders, policy beneficiaries, and people who are responsible for paying policy premiums. For each of these customer types, the insurance company needs different information. For a beneficiary, little is needed beyond an address. For a policy holder, health information is required. For the customer paying the premiums, information may be needed for tax purposes. Is it best to handle the separate kinds of customers as separate entities, or to handle the customer type as an attribute of the customer? There are limitations to both approaches: ♦ Building separate tables for each type of customer can lead to a very complex database design, and to multi-table queries when information relating to all customers is required. It is difficult, if using a single customer table, to ensure that the information for each customer is correct. Making columns required for some customers, but not for others, nullable permits the entry of correct data, but does not enforce it. There is no simple way in relational databases to tie default behavior to an attribute of the new entry.

Using classes to overcome relational database limitations
You can use a single customer table, with Java class columns for some of the information, to overcome the limitations of relational databases. For example, suppose different contact information is necessary for policy holders than for beneficiaries. You could approach this by defining a column based on a ContactInformation class. Then define classes named HolderContactInformation and BeneficiaryContactInformation, which are subclasses of the ContactInformation class. By entering new customers according to their type, you can be sure that the information is correct.

Levels of abstraction for relational data
Data in a relational database can be categorized by its purpose. Which of this data belongs in a Java class, and which is best kept in simple data type columns? 584

Chapter 18 Using Java in the Database

Referential integrity columns

Primary key columns and foreign key columns commonly hold identification numbers. These identification numbers may be called referential data; since they primarily define the structure of the database and the relationships between tables. Referential data does not generally belong in Java classes. Although you can make a Java class column a primary key column, integers and other simple data types are more efficient for this purpose.

Indexed data Columns that are commonly indexed may also belong outside a Java class. However, the dividing line between data that needs to be indexed and data that is not to be indexed is vaguely defined.

With computed columns you can selectively index on a Java field or method (or, in fact, some other expression). If you define a Java class column and then find that it would be useful to index on a field or method of that column, you can use computed columns to make a separate column from that field or method.

$ For more information, see "Using computed columns with Java
classes" on page 586. ♦
Descriptive data

It is common for some of the data in each row to be descriptive. It is not used for referential integrity purposes, and is possibly not frequently indexed, but it is data commonly used in queries. For an employee table, this may include information such as start date, address, benefit information, salary, and so on. This data can often benefit from being combined into fewer columns of Java class data types.

Java classes are useful for abstracting at a level between that of the single relational column and the relational table.

585

Using computed columns with Java classes

Using computed columns with Java classes
Computed columns are a feature designed to make Java database design easier, to make it easier to take advantage of Java features for existing databases, and to improve performance of Java data types. A computed column is a column whose values are obtained from other columns. You cannot INSERT or UPDATE values in computed columns. However, any update that attempts to modify the computed column does fire triggers associated with the column. Uses of computed columns There are two main uses of computed columns with Java classes: ♦
Exploding a Java column If you create a column using a Java class data type, computed columns enable you to index one of the fields of the class. You can add a computed column that holds the value of the field, and create an index on that field. Adding a Java column to a relational table If you wish to use some of the features of Java classes while disturbing an existing database as little as possible, you can add a Java column as a computed column, collecting its values from other columns in the table.

Defining computed columns
Computed columns are declared in the CREATE TABLE or ALTER TABLE statement. Creating tables with computed columns The following CREATE TABLE statement is used to create the product table in the Java sample tables:
CREATE TABLE product ( id INTEGER NOT NULL, JProd asademo.Product NOT NULL, name CHAR(15) COMPUTE ( JProd>>name ), PRIMARY KEY ("id") )

Adding computed columns to tables

The following statement alters the product table by adding another computed column:
ALTER TABLE product ADD inventory_Value INTEGER COMPUTE ( JProd.quantity * JProd.unit_price )

Modifying the expression for computed columns 586

You can change the expression used in a computed column using the ALTER TABLE statement. The following statement changes the expression that a computed column is based on.

Chapter 18 Using Java in the Database
ALTER TABLE table_name ALTER column-name SET COMPUTE ( expression )

The column is recalculated when this statement is executed. If the new expression is invalid, the ALTER TABLE statement fails. The following statement stops a column from being a computed column.
ALTER TABLE table_name ALTER column-name DROP COMPUTE

The values in the column are not changed when this statement is executed.

Inserting and updating computed columns
Computed columns have some impact on valid INSERT and UPDATE statements. The jdba.product table in the Java sample tables has a computed column (name) which we use to illustrate the issues. The table definition is as follows:
CREATE TABLE "jdba"."product" ( "id" INTEGER NOT NULL, "JProd" asademo.Product NOT NULL, "name" CHAR(15) COMPUTE( JProd.name ), PRIMARY KEY ("id") )

No direct inserts or updates You cannot insert a value directly into a computed column. The following statement fails with a Duplicate Insert Column error: -- Incorrect statement INSERT INTO PRODUCT (id, name) VALUES( 3006, ’bad insert statement’ )

Similarly, no UPDATE statement can directly update a computed column. ♦
Listing column names You must always specify column names in INSERT statements on tables with computed columns. The following statement fails with a Wrong Number of Values for Insert error: -- Incorrect statement INSERT INTO PRODUCT VALUES( 3007,new asademo.Product() )

Instead, you must list the columns, as follows:
INSERT INTO PRODUCT( id, JProd ) VALUES( 3007,new asademo.Product() )

587

Using computed columns with Java classes

Triggers You can define triggers on a computed column, and any INSERT or UPDATE statement that affects the column fires the trigger.

When computed columns are recalculated
Recalculating computed columns occurs when: ♦ ♦ ♦ ♦ ♦ Any column is deleted, added, or renamed The table is renamed Any column’s data type or COMPUTE clause is modified A row is inserted. A row is updated.

Computed columns are not recalculated when queried. If you use a timedependent expression, or one which depends on the state of the database in some other way, then the computed column may not give a proper result.

588

Chapter 18 Using Java in the Database

Configuring memory for Java
This section describes the memory requirements for running Java in the database and how to set up your server to meet those requirements. The Java VM requires a significant amount of cache memory. For information on tuning the cache, see "Using the cache to improve performance" on page 807. Database and connection-level requirements The Java VM uses memory on both a per-database and on a per-connection basis. ♦ The per database requirements are not relocatable: they cannot be paged out to disk. They must fit into the server cache. This type of memory is not for the server, it is for each database. When estimating cache requirements, you must sum the requirements for each database you run on the server. The per-connection requirements are relocatable, but only as a unit. The requirements for one connection are either all in cache, or all in the temporary file.

How memory is used
Java in the database requires memory for several purposes: ♦ When Java is first used when a server is running, the VM is loaded into memory, requiring over 1.5 Mb of memory. This is part of the databasewide requirements. An additional VM is loaded for each database that uses Java. For each connection that uses Java, a new instance of the VM loads for that connection. The new instance requires about 200K per connection. Each class definition that is used in a Java application is loaded into memory. This is held in database-wide memory: separate copies are not required for individual connections. Each connection requires a working set of Java variables and application stack space (used for method arguments and so on).

♦ ♦

♦ Managing memory

You can control memory use in the following ways: ♦
Set the overall cache size

You must use a cache size sufficient to meet all the requirements for non-relocatable memory.

The cache size is set when the server is started using the -c commandline switch. 589

Configuring memory for Java
In many cases, a cache size of 8 Mb is sufficient. ♦
Set the namespace size The Java namespace size is the maximum size, in bytes, of the per database memory allocation.

You can set this using the JAVA_NAMESPACE_SIZE option. The option is global, and can only be set by a user with DBA authority. ♦
Set the heap size

This JAVA_HEAP_SIZE option sets the maximum size, in bytes, of per connection memory. This option can be set for individual connections, but as it affects the memory available for other users it can be set only by a user with DBA authority.

Starting and stopping the VM

In addition to setting memory parameters for Java, you can unload the VM when Java is not in use using the STOP JAVA statement. Only a user with DBA authority can execute this statement. The syntax is simply:
STOP JAVA

The VM loads whenever a Java operation is carried out. If you wish to explicitly load it in readiness for carrying out Java operations, you can do so by executing the following statement:
START JAVA

590

C H A P T E R

1 9

Data Access Using JDBC

About this chapter

This chapter describes how to use JDBC to access data. JDBC can be used both from client applications and inside the database. Java classes using JDBC provide a more powerful alternative to SQL stored procedures for incorporating programming logic in the database.

Contents

Topic JDBC overview Establishing JDBC connections Using JDBC to access data Using the Sybase jConnect JDBC driver Creating distributed applications

Page 592 597 604 612 616

591

JDBC overview

JDBC overview
JDBC provides a SQL interface for Java applications: if you want to access relational data from Java, you do so using JDBC calls. Rather than a thorough guide to the JDBC database interface, this chapter provides some simple examples to introduce JDBC and illustrates how you can use it inside and outside the server. As well, this chapter provides more details on the server-side use of JDBC, running inside the database server.

$ The examples illustrate the distinctive features of using JDBC in Adaptive Server Anywhere. For more information about JDBC programming, see any JDBC programming book.
JDBC and Adaptive Server Anywhere You can use JDBC with Adaptive Server Anywhere in the following ways: ♦
JDBC on the client

Java client applications can make JDBC calls to Adaptive Server Anywhere. The connection takes place through the Sybase jConnect JDBC driver or through the JDBC-ODBC bridge. In this chapter, the phrase client application applies both to applications running on a user’s machine and to logic running on a middle-tier application server.

JDBC in the server

Java classes installed into a database can make JDBC calls to access and modify data in the database, using an internal JDBC driver.

The focus in this chapter is on server-side JDBC. JDBC resources ♦
Required software

You need TCP/IP to use the Sybase jConnect

driver. The Sybase jConnect driver may already be available, depending on your installation of Adaptive Server Anywhere.

$ For more information about the jConnect driver and its location,
see "The jConnect driver files" on page 612. ♦
Example source code You can find source code for the examples in this chapter in the file JDBCExamples.java in the jxmp subdirectory under your Adaptive Server Anywhere installation directory.

$ For instructions on how to set up the Java examples, including the
JDBCExamples class, see "Setting up the Java examples" on page 550.

JDBC program structure
The following sequence of events typically occur in JDBC applications: 592

Chapter 19 Data Access Using JDBC
1
Create a Connection object

Calling a getConnection class method of the DriverManager class creates a Connection object, and establishes a connection with a database. The Connection object generates a

2 3

Generate a Statement object

Statement object.
Pass a SQL statement A SQL statement that executed within the database environment passes to the Statement object. If the statement is a query, this action returns a ResultSet object.

The ResultSet object contains the data returned from the SQL statement, but exposes it one row at a time (similar to the way a cursor works). 4
Loop over the rows of the result set

The next method of the

ResultSet object performs two actions: ♦ ♦ 5 The current row (the row in the result set exposed through the ResultSet object) advances one row. A Boolean value (true/false) returns to indicate whether there is, in fact, a row to advance to.

For each row, retrieve the values

Values are retrieved for each column in the ResultSet object by identifying either the name or position of the column. You can use the getDate method to get the value from a column on the current row.

Java objects can use JDBC objects to interact with a database and get data for their own use, for example to manipulate or for use in other queries.

Server-side JDBC features
JDBC 1.2 is part of JDK 1.1. JDBC 2.0 is part of Java 2 (JDK 1.2). Java in the database supplies a subset of the JDK version 1.1, so the internal JDBC driver supports JDBC version 1.2. The internal JDBC driver (asajdbc) makes some features of JDBC 2.0 available from server-side Java applications, but does not provide full JDBC 2.0 support. The JDBC classes in the java.sql package that is part of the Java in the database support are at level 1.2. Server-side features that are part of JDBC 2.0 are implemented in the sybase.sql.ASA package. To use JDBC 2.0 features you must cast your JDBC objects into the corresponding classes in the sybase.sql.ASA package, rather than the java.sql package. Classes that are declared as java.sql are restricted to JDBC 1.2 functionality only. 593

JDBC overview
The classes in sybase.sql.ASA are as follows:
JDBC class java.sql.Connection java.sql.Statement java.sql.PreparedStatement java.sql.CallableStatement java.sql.ResultSetMetaData java.sql.ResultSet java.sql.DatabaseMetaData Sybase internal driver class sybase.sql.ASA.SAConnection sybase.sql.ASA.SAStatement sybase.sql.ASA.SAPreparedStatement sybase.sql.ASA.SACallableStatement sybase.sql.ASA.SAResultSetMetaData sybase.sql.SAResultSet sybase.sql.SADatabaseMetaData

The following function provides a ResultSetMetaData object for a prepared statement without requiring a ResultSet or executing the statement. This function is not part of the JDBC standard.
ResultSetMetaData sybase.sql.ASA.SAPreparedStatement.describe()

JDBC 2.0 restrictions

The following classes are part of the JDBC 2.0 core interface, but are not available in the sybase.sql.ASA package: ♦ ♦ ♦ ♦ ♦ ♦ java.sql.Blob java.sql.Clob java.sql.Ref java.sql.Struct java.sql.Array java.sql.Map

The following JDBC 2.0 core functions are not available in the sybase.sql.ASA package:

594

Chapter 19 Data Access Using JDBC

Class in sybase.sql.ASA SAConnection

Missing functions java.util.Map getTypeMap() void setTypeMap( java.util.Map map )

SAPreparedStatement

void setRef( int pidx, java.sql.Ref r ) void setBlob( int pidx, java.sql.Blob b ) void setClob( int pidx, java.sql.Clob c ) void setArray( int pidx, java.sql.Array a )

SACallableStatement

Object getObject( pidx, java.util.Map map ) java.sql.Ref getRef( int pidx ) java.sql.Blob getBlob( int pidx ) java.sql.Clob getClob( int pidx ) java.sql.Array getArray( int pidx )

SAResultSet

Object getObject( int cidx, java.util.Map map ) java.sql.Ref getRef( int cidx ) java.sql.Blob getBlob( int cidx ) java.sql.Clob getClob( int cidx ) java.sql.Array getArray( int cidx ) Object getObject( String cName, java.util.Map map ) java.sql.Ref getRef( String cName ) java.sql.Blob getBlob( String cName ) java.sql.Clob getClob( String cName ) java.sql.Array getArray( String cName )

Differences between client- and server-side JDBC connections
A difference between JDBC on the client and in the database server lies in establishing a connection with the database environment. ♦
Client side In client-side JDBC, establishing a connection requires the Sybase jConnect JDBC driver. Passing arguments to the DriverManager.getConnection establishes the connection. The database environment is an external application from the perspective of the client application.

595

JDBC overview

jConnect required

Depending on the package you received Adaptive Server Anywhere in, Sybase jConnect may or may not be included. You must have jConnect to use JDBC from external applications. You can use internal JDBC without jConnect. ♦ When using JDBC within the database server, a connection already exists. A value of jdbc:default:connection passes to DriverManager.getConnection, which provides the JDBC application with the ability to work within the current user connection. This is a quick, efficient and safe operation because the client application has already passed the database security to establish the connection. The user ID and password, having been provided once, do not need to be provided again. The asajdbc driver can only connect to the database of the current connection.
Server-side

You can write JDBC classes in such a way that they can run both at the client and at the server by employing a single conditional statement for constructing the URL. An external connection requires the machine name and port number, while the internal connection requires jdbc:default:connection.

596

Chapter 19 Data Access Using JDBC

Establishing JDBC connections
This section presents classes that establish a JDBC database connection from a Java application.

Connecting from a JDBC client application using jConnect
If you wish to access database system tables (database metadata) from a JDBC application, you must add a set of jConnect system objects to your database. Asajdbc shares the same stored procedures for database metadata support with jConnect. These procedures are installed to all databases by default. A dbinit switch "-I" prevents this installation.

$ For information about adding the jConnect system objects to a
database, see "Using the Sybase jConnect JDBC driver" on page 612. The following complete Java application is a command-line application that connects to a running database, prints a set of information to your command line, and terminates. Establishing a connection is the first step any JDBC application must take when working with database data.

$ This example illustrates an external connection, which is a regular client/server connection. For information on how to create an internal connection, from Java classes running inside the database server, see "Establishing a connection from a server-side JDBC class" on page 601.
External connection example code
The following is the source code for the methods used to make a connection. The source code can be found in the main method and the ASAConnect method of the file JDBCExamples.java in the jxmp directory under your Adaptive Server Anywhere installation directory:
// Import the necessary classes import java.sql.*; // import com.sybase.jdbc.*; // import java.util.Properties; // import sybase.sql.*; // import asademo.*; // private static Connection conn; public static void main(String args[]) conn = null; { JDBC Sybase jConnect Properties Sybase utilities Example classes

597

Establishing JDBC connections
String machineName; if ( args.length != 1 ) { machineName = "localhost"; } else { machineName = new String( args[0] ); } ASAConnect( "dba", "sql", machineName ); if( conn!=null ) { System.out.println( "Connection successful" ); }else{ System.out.println( "Connection failed" ); } try{ serializeVariable(); serializeColumn(); serializeColumnCastClass(); } catch( Exception e ) { System.out.println( "Error: " + e.getMessage() ); e.printStackTrace(); } } } private static void ASAConnect( String UserID, String Password, String Machinename ) { // uses global Connection variable String _coninfo = new String( Machinename ); Properties _props = new Properties(); _props.put("user", UserID ); _props.put("password", Password ); // Load the Sybase Driver try { Class.forName("com.sybase.jdbc.SybDriver").newInstance() ; StringBuffer temp = new StringBuffer(); // Use the Sybase jConnect driver... temp.append("jdbc:sybase:Tds:"); // to connect to the supplied machine name... temp.append(_coninfo); // on the default port number for ASA... temp.append(":2638"); // and connect. System.out.println(temp.toString());

598

Chapter 19 Data Access Using JDBC
conn = DriverManager.getConnection( temp.toString() , _props ); } catch ( Exception e ) { System.out.println("Error: " + e.getMessage()); e.printStackTrace(); } }

How the external connection example works
The external connection example is a Java command-line application. Importing packages The application requires several libraries, which are imported in the first lines of JDBCExamples.java: ♦ The java.sql package contains the Sun Microsystems JDBC classes, which are required for all JDBC applications. You’ll find it in the classes.zip file in your Java subdirectory. Imported from com.sybase.jdbc, the Sybase jConnect JDBC driver is required for all applications that connect using jConnect. You’ll find it in the jdbcdrv.zip file in your Java subdirectory. The application uses a property list. The java.util.Properties class is required to handle property lists. You’ll find it in the classes.zip file in your Java subdirectory. The sybase.sql package contains utilities used for serialization. You’ll find it in the asajdbc.zip file in your Java subdirectory. The asademo package contains example classes used in some examples. You’ll find it in the asademo.jar file in your jxmp subdirectory.

♦ ♦ The main method

Each Java application requires a class with a method named main, which is the method invoked when the program starts. In this simple example, JDBCExamples.main is the only method in the application. The JDBCExamples.main method carries out the following tasks: 1 Processes the command-line argument, using the machine name if supplied. By default, the machine name is localhost, which is appropriate for the personal database server. Calls the ASAConnect method to establish a connection. Executes several methods that scroll data to your command line.

2 3 The ASAConnect method

The JDBCExamples.ASAConnect method carries out the following tasks: 1 Connects to the default running database using Sybase jConnect.

599

Establishing JDBC connections
♦ ♦ Class.forName loads jConnect. Using the newInstance method works around issues in some browsers. The StringBuffer statements build up a connection string from the literal strings and the supplied machine name provided on the command line. DriverManager.getConnection establishes a connection using the connection string.

♦ 2

Returns control to the calling method.

Running the external connection example
This section describes how to run the external connection example
v To create and execute the external connection example application:

1 2 3

From a system command prompt, change to the Adaptive Server Anywhere installation directory. Change to the jxmp subdirectory Ensure that your CLASSPATH environment variable includes the current directory (.) and the imported zip files. For example, from a command prompt (the following should be entered all on one line):
set classpath=..\java\jdbcdrv.zip;.;..\java\asajdbc.zip; asademo.jar

The default zip file name for Java is classes.zip. For classes in any file named classes.zip, you only need the directory name in the CLASSPATH variable, not the zip-file name itself. For classes in files with other names, you must supply the zip file name. You need the current directory in the CLASSPATH to run the example. 4 Ensure the database is loaded onto a database server running TCP/IP. You can start such a server on your local machine using the following command (from the jxmp subdirectory):
start dbeng7 -c 8M ..\asademo

5

Enter the following at the command prompt to run the example:
java JDBCExamples

If you wish to try this against a server running on another machine, you must enter the correct name of that machine. The default is localhost, which is an alias for the current machine name.

600

Chapter 19 Data Access Using JDBC
6 Confirm that a list of people and products appears at your command prompt. If the attempt to connect fails, an error message appears instead. Confirm that you have executed all the steps as required. Check that your CLASSPATH is correct. An incorrect CLASSPATH results in a failure to locate a class.

$ For more information about using jConnect, see "Using the Sybase
jConnect JDBC driver" on page 612, and see the online documentation for jConnect.

Establishing a connection from a server-side JDBC class
SQL statements in JDBC are built using the createStatement method of a Connection object. Even classes running inside the server need to establish a connection to create a Connection object. Establishing a connection from a server-side JDBC class is more straightforward than establishing an external connection. Because a user already connected executes the server-side class, the class simply uses the current connection.

Server-side connection example code
The following is the source code for the example. You can find the source code in the InternalConnect method of JDBCExamples.java in the jxmp directory under your Adaptive Server Anywhere installation directory:
public static void InternalConnect() { try { conn = DriverManager.getConnection("jdbc:default:connection"); System.out.println("Hello World"); } catch ( Exception e ) { System.out.println("Error: " + e.getMessage()); e.printStackTrace(); } } }

How the server-side connection example works
In this simple example, InternalConnect() is the only method used in the application.

601

Establishing JDBC connections
The application requires only one of the libraries (JDBC) imported in the first line of the JDBCExamples.java class. The others are for external connections. The package named java.sql contains the JDBC classes. The InternalConnect() method carries out the following tasks: 1 Connects to the default running database using the current connection: ♦ 2 3 DriverManager.getConnection establishes a connection using a connection string of jdbc:default:connection.

Prints Hello World to the current standard output, which is the server window. System.out.println carries out the printing. If there is an error in the attempt to connect, an error message appears in the server window, together with the place where the error occurred. The try and catch instructions provide the framework for the error handling.

4

The class terminates.

Running the server-side connection example
This section describes how to run the server-side connection example.
v To create and execute the internal connection example application:

1

If you have not already done so, compile the JDBCExamples.java file. If you are using the JDK, you can do the following in the jxmp directory from a command prompt:
javac JDBCExamples.java

2

Start a database server using the sample database. You can start such a server on your local machine using the following command (from the jxmp subdirectory):
start dbeng7 ..\asademo

The TCP/IP network protocol is not necessary in this case, since you are not using jConnect. However, you must have at least 8 Mb of cache available to use Java classes in the database. 3 Install the class into the sample database. Once connected to the sample database, you can do this from Interactive SQL using the following command:
INSTALL JAVA NEW FROM FILE ’path\jxmp\JDBCExamples.class’

where path is the path to your installation directory. 602

Chapter 19 Data Access Using JDBC
You can also install the class using Sybase Central. While connected to the sample database, open the Java Objects folder and double-click Add Class. Then follow the instructions in the wizard. 4 You can now call the InternalConnect method of this class just as you would a stored procedure:
CALL JDBCExamples>>InternalConnect()

The first time a Java class is called in a session, the internal Java virtual machine must be loaded. This can take a few seconds. 5 Confirm that the message Hello World prints on the server screen.

Notes on JDBC connections

Autocommit behavior The JDBC specification requires that, by default, a COMMIT is performed after each data modification statement. Currently, the server-side JDBC behavior is to commit. You can control this behavior using a statement such as the following: conn.setAutoCommit( false ) ;

where conn is the current connection object. ♦
Connection defaults

From server-side JDBC, only the first call to getConnection( "jdbc:default:connection" ) creates a new connection with the default values. Subsequent calls return a wrapper of the current connection with all connection properties unchanged. If you set AutoCommit to OFF in your initial connection, any subsequent getConnection calls within the same Java code return a connection with AutoCommit set to OFF. You may wish to ensure that closing a connection resets connection properties to their default values, so subsequent connections are obtained with standard JDBC values. The following type of code achieves this:
Connection conn = DriverManager.getConnection(""); boolean oldAutoCommit = conn.getAutoCommit(); try { // do code here } finally { conn.setAutoCommit( oldAutoCommit ); }

This discussion applies not only to AutoCommit, but also to other connection properties such as TransactionIsolation and isReadOnly.

603

Using JDBC to access data

Using JDBC to access data
Java applications that hold some or all classes in the database have significant advantages over traditional SQL stored procedures. At an introductory level, however, it may be helpful to use the parallels with SQL stored procedures to demonstrate the